packages feed

FiniteCategories (empty) → 0.1.0.0

raw patch · 103 files changed

+7993/−0 lines, 103 filesdep +FiniteCategoriesdep +basedep +containers

Dependencies added: FiniteCategories, base, containers, directory, fgl, filepath, graphviz, process, random, text

Files

+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for FiniteCategories
+
+## 0.1.0.0 -- 2022-03-21
+
+* First version.
+ FiniteCategories.cabal view
@@ -0,0 +1,202 @@+cabal-version:      3.0
+
+-- Initial package description 'FiniteCategories.cabal' generated by
+-- 'cabal init'. For further documentation, see:
+--   http://haskell.org/cabal/users-guide/
+-- 
+-- The name of the package.
+name:               FiniteCategories
+
+-- The package version.
+-- See the Haskell package versioning policy (PVP) for standards
+-- guiding when and how versions should be incremented.
+-- https://pvp.haskell.org
+-- PVP summary:      +-+------- breaking API changes
+--                   | | +----- non-breaking API additions
+--                   | | | +--- code changes with no API change
+version:            0.1.0.0
+
+-- A short (one-line) description of the package.
+synopsis: Finite categories and usual categorical constructions on them.
+    
+
+-- A longer description of the package.
+description: This package provides tools to create categories at the value level. This is different from the __Hask__ category where types are objects in a category with infinite objects and arrows, here we construct categories where objects and arrows are arbitrary values so that we can change categories during runtime. Each category implements three functions following the category structure axioms : @ob@ which returns objects of the category, @ar@ which returns arrows between two objects of the category and @identity@ which returns the identity of an object. Thanks to theses functions, we can construct automatically all the usual constructions on the categories (limits and colimits, adjunctions, Yoneda embedding, etc.) Functors are different from usual @Functor@ typeclass, we store functors as mapping between objects and morphisms of two categories. This package is also different from the package @data-category@ because we can enumerate objects and arrows in a category.  This allows us to construct limit, colimits, adjunctions, etc. automatically for arbitrary finite categories. On the other hand, we loose typecheck at compilation time which ensures that composition is sound in __Hask__, composition in our package might lead to an error raised during runtime. See the Readme file for installation help.
+
+-- URL for the project homepage or repository.
+homepage: https://gitlab.utc.fr/gsabbagh/FiniteCategories
+
+-- A URL where users can report bugs.
+-- bug-reports: 
+
+-- The license under which the package is released.
+license:            GPL-3.0-or-later
+
+-- The file containing the license text.
+license-file:       LICENSE
+
+-- The package author(s).
+author:             Guillaume Sabbagh
+
+-- An email address to which users can send suggestions, bug reports, and patches.
+maintainer:         guillaumesabbagh@protonmail.com
+
+-- A copyright notice.
+-- copyright:
+category:           Data, Maths
+
+-- Extra files to be distributed with the package, such as examples or a README.
+extra-source-files:
+    CHANGELOG.md
+    Readme.md
+    test/ExampleAdjunction/ExampleAdjunction.scg
+    test/ExampleAdjunction/ExampleAdjunctionDiag1.fscg
+    test/ExampleAdjunction/ExampleAdjunctionDiag2.fscg
+    test/ExampleParsers/Example.fscg
+    test/ExampleParsers/Example.scg
+    test/ExampleParsers/Example2.scg
+
+library
+    -- Modules exported by the library.
+    exposed-modules:    CompositionGraph.CompositionGraph, 
+                        CompositionGraph.SafeCompositionGraph,
+                        ExportGraphViz.ExportGraphViz,
+                        FiniteCategory.FiniteCategory,
+                        RandomCompositionGraph.RandomCompositionGraph,
+                        Set.FinOrdSet,
+                        Utils.CartesianProduct,
+                        IO.CreateAndWriteFile,
+                        Utils.Sample,
+                        Utils.Tuple,
+                        Cat.FinCat,
+                        Utils.EnumerateMaps,
+                        Diagram.Diagram,
+                        UsualCategories.DiscreteCategory,
+                        UsualCategories.One,
+                        UsualCategories.Two,
+                        UsualCategories.Three,
+                        UsualCategories.Zero,
+                        UsualCategories.Parallel,
+                        CommaCategory.CommaCategory,
+                        FunctorCategory.FunctorCategory,
+                        DiagonalFunctor.DiagonalFunctor,
+                        ConeCategory.ConeCategory,
+                        RandomDiagram.RandomDiagram,
+                        IO.PrettyPrint,
+                        IO.Show,
+                        Utils.AssociationList,
+                        Cat.PartialFinCat,
+                        Utils.SetList,
+                        Config.Config,
+                        Diagram.Conversion,
+                        Subcategories.FreeSubcategory,
+                        IO.Parsers.Lexer,
+                        IO.Parsers.CompositionGraph,
+                        IO.Parsers.SafeCompositionGraph,
+                        IO.Parsers.SafeCompositionGraphFunctor,
+                        ConeCategory.LeftCone,
+                        OppositeCategory.OppositeCategory,
+                        Set.FinSet,
+                        YonedaEmbedding.YonedaEmbedding,
+                        Subcategories.Subcategory,
+                        Subcategories.FullSubcategory,
+                        UsualCategories.V,
+                        UsualCategories.Hat,
+                        ProductCategory.ProductCategory,
+                        Currying.Currying,
+                        UsualCategories.Square,
+                        Adjunction.Adjunction,
+                        Limit.Limit
+
+    -- Modules included in this library but not exported.
+    -- other-modules:  
+
+    -- LANGUAGE extensions used by modules in this package.
+    other-extensions: MultiParamTypeClasses, FunctionalDependencies, UndecidableInstances, FlexibleInstances
+
+    -- Other library packages from which modules are imported.
+    build-depends:      base             >=4.15.0.0 && < 4.16,
+                        containers       >= 0.6.4 && < 0.7,
+                        directory        >= 1.3.6 && < 1.4,
+                        filepath         >= 1.4.2 && < 1.5,
+                        fgl              >= 5.7.0 && < 5.8,
+                        graphviz         >= 2999.20.1 && < 2999.21,
+                        text             >= 1.2.4 && < 1.3,
+                        process          >= 1.6.11 && < 1.7,
+                        random           >= 1.2.1 && < 1.3,
+
+    -- Directories containing source files.
+    hs-source-dirs:   src
+
+    -- Base language which the package is written in.
+    default-language: Haskell2010
+
+test-suite FiniteCategories-test
+    -- Base language which the package is written in.
+    default-language: Haskell2010
+
+    -- The interface type and version of the test suite.
+    type:             exitcode-stdio-1.0
+
+    -- Directories containing source files.
+    hs-source-dirs:   test
+
+    -- The entrypoint to the test suite.
+    main-is:          RunAllExamples.hs
+
+    -- Test dependencies.
+    build-depends:      FiniteCategories,
+                        base             >=4.15.0.0 && < 4.16,
+                        containers       >= 0.6.4 && < 0.7,
+                        directory        >= 1.3.6 && < 1.4,
+                        filepath         >= 1.4.2 && < 1.5,
+                        fgl              >= 5.7.0 && < 5.8,
+                        graphviz         >= 2999.20.1 && < 2999.21,
+                        text             >= 1.2.4 && < 1.3,
+                        process          >= 1.6.11 && < 1.7,
+                        random           >= 1.2.1 && < 1.3,
+
+    other-modules:  ExampleAdjunction.ExampleAdjunction
+                    ExampleCat.ExampleCat
+                    ExampleCat.ExampleFunctor
+                    ExampleCat.ExamplePartialFinCat
+                    ExampleCommaCategory.ExampleArrowCategory
+                    ExampleCommaCategory.ExampleCosliceCategory
+                    ExampleCommaCategory.ExampleSliceCategory
+                    ExampleCompositionGraph.ExampleCompositionGraph
+                    ExampleCompositionGraph.ExampleCompositionGraphConstruction
+                    ExampleCompositionGraph.ExampleFinSetToCompositionGraph
+                    ExampleCompositionGraph.ExampleSafeCompositionGraph
+                    ExampleConeCategory.ExampleCoconeCategory
+                    ExampleConeCategory.ExampleColimit
+                    ExampleConeCategory.ExampleConeCategory
+                    ExampleConeCategory.ExampleLeftCone
+                    ExampleConeCategory.ExampleLimit
+                    ExampleCurrying.ExampleCurrying
+                    ExampleDiagonalFunctor.ExampleDiagonalFunctor
+                    ExampleDiagram.ExampleConstantDiagram
+                    ExampleDiagram.ExampleConversion
+                    ExampleDiagram.ExampleDiagram
+                    ExampleDiagram.ExampleDiscreteDiagram
+                    ExampleDiagram.ExampleIdentityDiagram
+                    ExampleDiagram.ExampleParallelDiagram
+                    ExampleDiagram.ExampleSelectOneDiagram
+                    ExampleDiagram.ExampleSelectThreeDiagram
+                    ExampleDiagram.ExampleSelectTwoDiagram
+                    ExampleDiagram.ExampleSelectZeroDiagram
+                    ExampleFunctorCategory.ExampleFunctorCategory
+                    ExampleOppositeCategory.ExampleOppositeCategory
+                    ExampleParsers.ExampleSafeCompositionGraph
+                    ExampleParsers.ExampleSafeCompositionGraphFunctor
+                    ExampleProductCategory.ExampleProductCategory
+                    ExampleRandomCompositionGraph.ExampleRandomCompositionGraph
+                    ExampleRandomDiagram.ExampleRandomDiagram
+                    ExampleRandomDiagram.ExampleRandomTriangle
+                    ExampleSet.ExampleCompletion
+                    ExampleSet.ExampleOrdSet
+                    ExampleSet.ExamplePowerOrdSet
+                    ExampleSet.ExamplePowerSet
+                    ExampleSet.ExampleSet
+                    ExampleSubcategories.ExampleFreeSubcategory
+                    ExampleYonedaEmbedding.ExampleYonedaEmbedding
+   
+ LICENSE view
@@ -0,0 +1,674 @@+              GNU GENERAL PUBLIC LICENSE
+                Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                     Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+              END OF TERMS AND CONDITIONS
+
+     How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+ Readme.md view
@@ -0,0 +1,59 @@+# FiniteCategories
+
+The goal of this project is to represent small finite categories in order to make usual constructions automatically on them (e.g. (co)limits, (co)completion, adjunctions, etc.)
+
+## Table of Contents
+1. [General Info](#general-info)
+2. [Technologies](#technologies)
+3. [Installation](#installation)
+4. [Collaboration](#collaboration)
+5. [Examples](#examples)
+
+## General Info
+
+This package provides tools to create categories at the value level. This is different from the __Hask__ category where types are objects in a category with infinite objects and arrows, here we construct categories where objects and arrows are arbitrary values so that we can change categories during runtime. Each category implements three functions following the category structure axioms : `ob` which returns objects of the category, `ar` which returns arrows between two objects of the category and `identity` which returns the identity of an object. Thanks to theses functions, we can construct automatically all the usual constructions on the categories (limits and colimits, adjunctions, Yoneda embedding, etc.) Functors are different from usual `Functor` typeclass, we store functors as mapping between objects and morphisms of two categories.
+
+This package is also different from the package `data-category` because we can enumerate objects and arrows in a category.  This allows us to construct limit, colimits, adjunctions, etc. automatically for arbitrary finite categories. On the other hand, we loose typecheck at compilation time which ensures that composition is sound in __Hask__, composition in our package might lead to an error raised during runtime.
+
+## Technologies
+
+The project uses GraphViz for visualizing the categories created.
+
+There is another version programmed in Python : [repository link](https://gitlab.utc.fr/gsabbagh/modification-de-categories)
+
+## Installation
+
+To use the graphviz exports, you must first install graphviz (see [graphviz website](https://graphviz.org/download/)) and make sure that Graphviz folder is in the path (dot should be a callable program from your terminal, if you are on Windows see [this tutorial](https://stackoverflow.com/questions/44272416/how-to-add-a-folder-to-path-environment-variable-in-windows-10-with-screensho#44272417) and if you are on unix see [this tutorial]( https://unix.stackexchange.com/questions/26047/how-to-correctly-add-a-path-to-path)).
+
+## Collaboration
+
+All contributions are appreciated! Contact me by email for any information.
+
+## Usage
+
+To run all examples of the project, run in a terminal the following command :
+
+```cabal test```
+
+You can then find the graphviz output in the folder `OutputGraphViz/`.
+
+The first files you should inspect in the documentation are `FiniteCategory.FiniteCategory` and `CompositionGraph.CompositionGraph`. They are the most useful to understand and create new categories from scratch.
+You can also take a look at the examples in the test suite.
+
+## Examples
+
+A category exported with graphviz looks like the following image : 
+
+![Category](https://gitlab.utc.fr/gsabbagh/FiniteCategories/-/raw/master/Images/ExampleCategory.png)
+
+A diagram on this category selecting two objects C and D is represented next :
+
+![Diagram](https://gitlab.utc.fr/gsabbagh/FiniteCategories/-/raw/master/Images/ExampleDiagram.png)
+
+A cone on this diagram follows, the apex of the cone is in green, its legs are in yellow and the diagram is in blue :
+
+![Cone](https://gitlab.utc.fr/gsabbagh/FiniteCategories/-/raw/master/Images/ExampleCone.png)
+
+The limiting cone is represented below, it is the product of the two objects C and D.
+
+![Limit](https://gitlab.utc.fr/gsabbagh/FiniteCategories/-/raw/master/Images/ExampleLimit.png)
+ src/Adjunction/Adjunction.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE MultiParamTypeClasses  #-}
+{-| Module  : FiniteCategories
+Description : Adjoint functors.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Adjunctions are all over the place in mathematics.
+-}
+
+module Adjunction.Adjunction 
+(
+    leftAdjoint,
+    rightAdjoint,
+)
+where
+    import              FiniteCategory.FiniteCategory
+    import              Diagram.Diagram
+    import              CommaCategory.CommaCategory
+    import              Data.Maybe                          (fromJust)
+    import              Utils.AssociationList
+    
+    -- | Returns the left adjoint of a functor, if the left adjoint does not exist, returns a partial Diagram being the best ajoint we could construct.
+    leftAdjoint :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1,
+                     FiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2) =>
+                     Diagram c1 m1 o1 c2 m2 o2 -> Diagram c2 m2 o2 c1 m1 o1
+    leftAdjoint g = Diagram {
+                        src = tgt g,
+                        tgt = src g,
+                        omap = [(y, indexTgt.head.universalMorphisms $ y) | y <- ob (tgt g), not (null (universalMorphisms y))],
+                        mmap = [(m, head (binding m)) | m <- arrows (tgt g), not (null (binding m))]
+                    }
+        where
+            universalMorphisms y = initialObjects (CommaCategory {rightDiag = g, leftDiag = fromJust (mkSelect1 (tgt g) y)})
+            binding m = [a | a <- arrows (src g), (not (null (universalMorphisms (source m)))) && (not (null (universalMorphisms (target m)))) && ((target ((mmap g) !-! a)) == (source (arrow.head.universalMorphisms $ target m))) && (((arrow.head.universalMorphisms $ target m) @ m) == ((mmap g) !-! a) @ (arrow.head.universalMorphisms $ source m))]
+    
+    -- | Returns the right adjoint of a functor, if the right adjoint does not exist, returns a partial Diagram being the best ajoint we could construct.
+    rightAdjoint :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1,
+                     FiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2) =>
+                     Diagram c2 m2 o2 c1 m1 o1 -> Diagram c1 m1 o1 c2 m2 o2
+    rightAdjoint f = Diagram {
+                        src = tgt f,
+                        tgt = src f,
+                        omap = [(x, indexSrc.head.universalMorphisms $ x) | x <- ob (tgt f), not (null (universalMorphisms x))],
+                        mmap = [(m, head (binding m)) | m <- arrows (tgt f), (not (null (universalMorphisms (source m)))) && (not (null (universalMorphisms (target m)))) && not (null (binding m))]
+                    }
+        where
+            universalMorphisms x = terminalObjects (CommaCategory {leftDiag = f, rightDiag = fromJust (mkSelect1 (tgt f) x)})
+            binding m = [a | a <- ar (src f) (indexSrc.head.universalMorphisms $ (source m)) (indexSrc.head.universalMorphisms $ (target m)), ((arrow.head.universalMorphisms $ target m) @ ((mmap f) !-! a)) == (m @ (arrow.head.universalMorphisms $ source m))]
+ src/Cat/FinCat.hs view
@@ -0,0 +1,94 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses  #-}
+
+{-| Module  : FiniteCategories
+Description : __FinCat__ is the category of finite categories, functors are the morphisms of __FinCat__.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+The __FinCat__ category has as objects finite categories and as morphisms functors between them.
+It is itself a large category (therefore not a finite one),
+we only construct finite full subcategories of the mathematical infinite __FinCat__ category.
+`FinCat` is the type of full finite subcategories of __FinCat__.
+
+To instantiate it, use the `FinCat` constructor on a list of categories.
+
+For example, see ExampleCat.ExampleCat
+
+The `FinCat` type should not be confused with the `FiniteCategory` typeclass.
+
+The `FiniteCategory` typeclass describes axioms a structure should follow to be considered a finite category.
+
+The `FinCat` type is itself a `FiniteCategory` and contains finite categories as objects.
+
+To convert a `FinFunctor` into any other kind of functor, see @Diagram.Conversion@.
+-}
+
+module Cat.FinCat
+(
+    FinFunctor(..),
+    FinCat(..)
+)
+where
+    import FiniteCategory.FiniteCategory
+    import Utils.EnumerateMaps
+    import Utils.CartesianProduct
+    import IO.PrettyPrint
+    import IO.Show
+    import Utils.AssociationList
+    
+    -- | A `FinFunctor` /F/ between two categories is a map between objects and a map between arrows of the two categories such that :
+    --
+    -- prop> F (srcF f) = srcF (F f) 
+    -- prop> F (tgtF f) = tgtF (F f)
+    -- prop> F (f @ g) = F(f) @ F(g)
+    -- prop> F (identity a) = identity (F a)
+    --
+    -- It is meant to be a morphism between categories within `FinCat`, it is homogeneous, the type of the source category must be the same as the type of the target category.
+    --
+    -- See /Diagram/ for heterogeneous ones.
+    --
+    -- To convert a `FinFunctor` into any other kind of functor, see @Diagram.Conversion@.
+    data FinFunctor c m o = FinFunctor {srcF :: c, tgtF :: c, omapF :: AssociationList o o, mmapF :: AssociationList m m} deriving (Eq, Show)
+    
+    instance (Eq c, Eq m, Eq o) => Morphism (FinFunctor c m o) c where
+        (@) FinFunctor{srcF=s2,tgtF=t2,omapF=om2,mmapF=fm2} FinFunctor{srcF=s1,tgtF=t1,omapF=om1,mmapF=fm1}
+            | t1 /= s2 = error "Illegal composition of FinFunctors."
+            | otherwise = FinFunctor{srcF=s1,tgtF=t2,omapF=om2!-.om1,mmapF=fm2!-.fm1}
+        source = srcF
+        target = tgtF
+                    
+    instance (FiniteCategory c m o, Morphism m o, PrettyPrintable c, PrettyPrintable m, PrettyPrintable o, Eq m, Eq o) =>
+              PrettyPrintable (FinFunctor c m o) where
+        pprint FinFunctor{srcF=s,tgtF=t,omapF=om,mmapF=fm} = "FinFunctor ("++pprint s++") -> ("++pprint t++")\n"++pprint om++"\n"++pprint fm
+        
+    -- | Checks wether the properties of a FinFunctor are respected.
+    checkFinFunctoriality :: (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => FinFunctor c m o -> Bool
+    checkFinFunctoriality FinFunctor {srcF=s,tgtF=t,omapF=om,mmapF=fm}
+        | not (and imIdNotId) = False
+        | not (and errFunct) = False
+        | otherwise = True
+        where
+            imIdNotId = [fm !-! (identity s a) == identity t (om !-! a) | a <- ob s]
+            errFunct = [fm !-! (g @ f) == (fm !-! g) @ (fm !-! f) | f <- (arrows s), g <- (arFrom s (target f))]
+        
+    -- | An instance of `FinCat` is a list of categories of interest.
+    --
+    -- Listing all arrows between two objects (i.e. listing FinFunctors between two categories) is slow (there are a lot of candidates).
+    newtype FinCat c m o = FinCat [c]
+    
+    -- We are forced to use the language extension FlexibleInstances because of this instance declaration :
+    -- The category 'c' could be itself a `FinCat` category therefore not respecting the uniqueness rule of instanciation.
+    instance (FiniteCategory c m o, Morphism m o, Eq c, Eq m, Eq o) => FiniteCategory (FinCat c m o) (FinFunctor c m o) c where
+        ob (FinCat xs) = xs
+        identity finCat catObj = FinFunctor {srcF=catObj,tgtF=catObj,omapF=functToAssocList id (ob catObj),mmapF=functToAssocList id (arrows catObj)}
+        ar finCat cat1 cat2 = [FinFunctor{srcF=cat1,tgtF=cat2,mmapF=appF, omapF=appO} | appO <- appObj, appF <- concat <$> cartesianProduct [twoObjToMaps a b appO| a <- ob cat1, b <- ob cat1], checkFinFunctoriality FinFunctor{srcF=cat1,tgtF=cat2,mmapF=appF, omapF=appO}]
+            where
+                appObj = enumMaps (ob cat1) (ob cat2)
+                twoObjToMaps a b appO = enumMaps (ar cat1 a b) (ar cat2 (appO !-! a) (appO !-! b))
+                    
+    instance (FiniteCategory c m o, Morphism m o, Eq c, Eq m, Eq o) => GeneratedFiniteCategory (FinCat c m o) (FinFunctor c m o) c where
+        genAr = defaultGenAr
+        decompose = defaultDecompose
+ src/Cat/PartialFinCat.hs view
@@ -0,0 +1,147 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses  #-}
+
+{-| Module  : FiniteCategories
+Description : __PartialFinCat__ is the category of finite categories, partial functors are the morphisms of __FinCat__.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+The __PartialFinCat__ category has as objects finite categories and as morphisms partial functors between them.
+
+A partial functor is a functor where the object map and the morphism map can be partial functions.
+
+It is itself a large category (therefore not a finite one),
+we only construct finite full subcategories of the mathematical infinite __PartialFinCat__ category.
+`PartialFinCat` is the type of full finite subcategories of __PartialFinCat__.
+
+To instantiate it, use the `PartialFinCat` constructor on a list of categories.
+
+To convert a `PartialFunctor` into any other kind of functor, see @Diagram.Conversion@.
+
+For example, see @ExampleCat.ExamplePartialFinCat@.
+-}
+
+module Cat.PartialFinCat
+(
+    PartialFunctor(..),
+    PartialFinCat(..),
+    domainObjects,
+    domainArrows,
+    codomainObjects,
+    codomainArrows,
+    objectsNotMapped,
+    arrowsNotMapped,
+    objectsNotMappedTo,
+    arrowsNotMappedTo
+)
+where
+    import FiniteCategory.FiniteCategory
+    import Cat.FinCat
+    import Utils.EnumerateMaps
+    import Utils.CartesianProduct
+    import Utils.AssociationList
+    import IO.PrettyPrint
+    import IO.Show
+    import Utils.SetList
+    import Data.List ((\\), nub)
+    
+    -- | A `PartialFunctor` /F/ between two categories is a partial map between objects and a partial map between arrows of the two categories such that :
+    --
+    -- prop> F (srcPF f) = srcPF (F f) 
+    -- prop> F (tgtPF f) = tgtPF (F f)
+    -- prop> F (f @ g) = F(f) @ F(g)
+    -- prop> F (identity a) = identity (F a)
+    --
+    -- It is meant to be a morphism between categories within `PartialFinCat`, it is homogeneous, the type of the source category must be the same as the type of the target category.
+    --
+    -- To convert a `PartialFunctor` into any other kind of functor, see @Diagram.Conversion@.
+    data PartialFunctor c m o = PartialFunctor {srcPF :: c, tgtPF :: c, omapPF :: AssociationList o o, mmapPF :: AssociationList m m} deriving (Eq, Show)
+    
+    instance (Eq c, Eq m, Eq o) => Morphism (PartialFunctor c m o) c where
+        (@) PartialFunctor{srcPF=s2,tgtPF=t2,omapPF=om2,mmapPF=fm2} PartialFunctor{srcPF=s1,tgtPF=t1,omapPF=om1,mmapPF=fm1}
+            | t1 /= s2 = error "Illegal composition of PartialFunctors."
+            | otherwise = PartialFunctor{srcPF=s1,tgtPF=t2,omapPF=om2 !-. om1,mmapPF=fm2 !-. fm1}
+        source = srcPF
+        target = tgtPF
+            
+    instance (FiniteCategory c m o, Morphism m o, PrettyPrintable c, PrettyPrintable m, PrettyPrintable o, Eq m, Eq o) =>
+              PrettyPrintable (PartialFunctor c m o) where
+        pprint PartialFunctor{srcPF=s,tgtPF=t,omapPF=om,mmapPF=fm} = "PartialFunctor ("++pprint s++") -> ("++pprint t++")\n\n"++pprint om++"\n\n"++pprint fm
+        
+    -- -- | Checks wether the properties of a functor are respected.
+    checkPartialFunctoriality :: (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => PartialFunctor c m o -> Bool
+    checkPartialFunctoriality PartialFunctor {srcPF=s,tgtPF=t,omapPF=om,mmapPF=fm}
+        | not ((keys om) `isIncludedIn` (ob s)) = False
+        | not ((keys fm) `isIncludedIn` (arrows s)) = False
+        | not (and imSrcExists) = False
+        | not (and imTgtExists) = False
+        | not (and idMapped) = False
+        | not (and imIdNotId) = False
+        | not (and compNotMapped) = False
+        | not (and errFunct) = False
+        | otherwise = True
+        where
+            imSrcExists = [elem (source f) (keys om) | f <- keys fm]
+            imTgtExists = [elem (target f) (keys om) | f <- keys fm]
+            idMapped = [elem (identity s o) (keys fm) | o <- keys om]
+            imIdNotId = [fm !-! (identity s a) == identity t (om !-! a) | a <- keys om]
+            compNotMapped = [elem (g @ f) (keys fm) | f <- (arrows s), g <- (arFrom s (target f)), elem f (keys fm), elem g (keys fm)]
+            errFunct = [fm !-! (g @ f) == (fm !-! g) @ (fm !-! f) | f <- (arrows s), g <- (arFrom s (target f)), elem f (keys fm), elem g (keys fm)]
+      
+    -- | An instance of `PartialFinCat` is a list of categories of interest.
+    --
+    -- Listing all arrows between two objects (i.e. listing PartialFunctors between two categories) is slow (there are a lot of candidates).
+    newtype PartialFinCat c m o = PartialFinCat [c]
+    
+    -- We are forced to use the language extension FlexibleInstances because of this instance declaration :
+    -- The category 'c' could be itself a `FinCat` category therefore not respecting the uniqueness rule of instanciation.
+    instance (FiniteCategory c m o, Morphism m o, Eq c, Eq m, Eq o) => FiniteCategory (PartialFinCat c m o) (PartialFunctor c m o) c where
+        ob (PartialFinCat xs) = xs
+        identity (PartialFinCat xs) catObj
+            | elem catObj xs = PartialFunctor {srcPF=catObj,tgtPF=catObj,omapPF=mkAssocListIdentity (ob catObj),mmapPF=mkAssocListIdentity (arrows catObj)}
+            | otherwise = error "Category not in PartialFinCat"
+        ar (PartialFinCat xs) cat1 cat2
+            | elem cat1 xs && elem cat2 xs = [PartialFunctor{srcPF=cat1,tgtPF=cat2,mmapPF=appF, omapPF=appO} | appO <- appObj, appF <- appMorph, checkPartialFunctoriality PartialFunctor{srcPF=cat1,tgtPF=cat2,mmapPF=appF, omapPF=appO}]
+            | otherwise = error "Category not in PartialFinCat"
+            where
+                appObj = concat $ (\x -> enumAssocLists x (ob cat2)) <$> (powerList (ob cat1))
+                appMorph = concat $ (\x -> enumAssocLists x (arrows cat2)) <$> (powerList (arrows cat1))
+                    
+    instance (FiniteCategory c m o, Morphism m o, Eq c, Eq m, Eq o) => GeneratedFiniteCategory (PartialFinCat c m o) (PartialFunctor c m o) c where
+        genAr = defaultGenAr
+        decompose = defaultDecompose
+    
+    -- | Returns the objects mapped by a partial functor.
+    domainObjects :: (FiniteCategory c m o, Morphism m o, Eq c, Eq m, Eq o) => PartialFunctor c m o -> [o]
+    domainObjects funct = keys (omapPF funct)
+    
+    -- | Returns the objects not mapped by a partial functor.
+    objectsNotMapped :: (FiniteCategory c m o, Morphism m o, Eq c, Eq m, Eq o) => PartialFunctor c m o -> [o]
+    objectsNotMapped funct = (ob (source funct))\\(domainObjects funct)
+    
+    -- | Returns the arrows mapped by a partial functor.
+    domainArrows :: (FiniteCategory c m o, Morphism m o, Eq c, Eq m, Eq o) => PartialFunctor c m o -> [m]
+    domainArrows funct = keys (mmapPF funct)
+    
+    -- | Returns the arrows not mapped by a partial functor.
+    arrowsNotMapped :: (FiniteCategory c m o, Morphism m o, Eq c, Eq m, Eq o) => PartialFunctor c m o -> [m]
+    arrowsNotMapped funct = (arrows (source funct))\\(domainArrows funct)
+
+    -- | Returns the objects mapped onto by a partial functor.
+    codomainObjects :: (FiniteCategory c m o, Morphism m o, Eq c, Eq m, Eq o) => PartialFunctor c m o -> [o]
+    codomainObjects funct = nub $ values (omapPF funct)
+
+    -- | Returns the objects not mapped onto by a partial functor.
+    objectsNotMappedTo :: (FiniteCategory c m o, Morphism m o, Eq c, Eq m, Eq o) => PartialFunctor c m o -> [o]
+    objectsNotMappedTo funct = (ob (target funct))\\(codomainObjects funct)
+    
+    -- | Returns the arrows mapped onto by a partial functor.
+    codomainArrows :: (FiniteCategory c m o, Morphism m o, Eq c, Eq m, Eq o) => PartialFunctor c m o -> [m]
+    codomainArrows funct = nub $ values (mmapPF funct)
+
+    -- | Returns the arrows not mapped onto by a partial functor.
+    arrowsNotMappedTo :: (FiniteCategory c m o, Morphism m o, Eq c, Eq m, Eq o) => PartialFunctor c m o -> [m]
+    arrowsNotMappedTo funct = (arrows (target funct))\\(codomainArrows funct)
+    
+ src/CommaCategory/CommaCategory.hs view
@@ -0,0 +1,109 @@+{-# LANGUAGE MultiParamTypeClasses  #-}
+
+{-| Module  : FiniteCategories
+Description : A comma category is a category where objects are morphisms of another category /C/ and morphisms are commutative squares in /C/.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+A comma category is a category where objects are morphisms of another category /C/ and morphisms are commutative squares in /C/.
+
+For example, see Examples.ExampleCommaCategory.*
+-}
+
+module CommaCategory.CommaCategory
+(
+    CommaObject(..),
+    CommaMorphism(..),
+    CommaCategory(..),
+    mkSliceCategory,
+    mkCosliceCategory,
+    mkArrowCategory,
+)
+where
+    import FiniteCategory.FiniteCategory
+    import Diagram.Diagram
+    import UsualCategories.One
+    import IO.PrettyPrint
+    import Utils.AssociationList
+    
+    -- | A `CommaObject` in the `CommaCategory` (/T/|/S/) is a triplet \</e/,/d/,/f/\> where @f : /T/(e) -> /S/(d)@.
+    --
+    -- See /Categories for the working mathematician/, Saunders Mac Lane, P.46.
+    data CommaObject o1 o2 m3 = CommaObject {indexSrc :: o1 -- ^ /e/
+                                        , indexTgt :: o2 -- ^ /d/
+                                        , arrow :: m3} -- ^ /f/
+                                        deriving (Eq, Show)
+    
+    instance (PrettyPrintable o1, PrettyPrintable o2, PrettyPrintable m3) =>
+             PrettyPrintable (CommaObject o1 o2 m3) where
+        pprint CommaObject{indexSrc=e, indexTgt=d, arrow=f} = "<"++pprint e++", "++pprint d++", "++pprint f++">"
+    
+    -- | A `CommaMorphism` in the `CommaCategory` (/T/|/S/) is a couple \</k/,/h/\>.
+    --
+    -- See /Categories for the working mathematician/, Saunders Mac Lane, P.46.
+    data CommaMorphism o1 o2 m1 m2 m3 = CommaMorphism {srcCM :: (CommaObject o1 o2 m3) -- ^ The source `CommaObject`
+                                                     , tgtCM :: (CommaObject o1 o2 m3) -- ^ The target `CommaObject`
+                                                     , indexAr1 :: m1 -- ^ /k/
+                                                     , indexAr2 :: m2} -- ^ /h/
+                                                     deriving (Eq, Show)
+                                                     
+    instance (PrettyPrintable m1, PrettyPrintable m2) =>
+              PrettyPrintable (CommaMorphism o1 o2 m1 m2 m3) where
+        pprint CommaMorphism{srcCM=_, tgtCM =_, indexAr1=k, indexAr2=h} = "<"++pprint k++", "++pprint h++">"
+    
+    instance (Morphism m1 o1, Morphism m2 o2, Eq o1, Eq o2, Eq m3) => Morphism (CommaMorphism o1 o2 m1 m2 m3) (CommaObject o1 o2 m3) where
+        (@) CommaMorphism{srcCM=s2,tgtCM=t2,indexAr1=k2,indexAr2=h2} CommaMorphism{srcCM=s1,tgtCM=t1,indexAr1=k1,indexAr2=h1}
+            | t1 /= s2 = error "Illegal composition of CommaMorphism."
+            | otherwise = CommaMorphism {srcCM=s1,tgtCM=t2,indexAr1=k2 @ k1,indexAr2=h2 @ h1}
+        source = srcCM
+        target = tgtCM
+    
+    -- | A `CommaCategory` is a couple (/T/|/S/) with /T/ and /S/ two diagrams with the same target.
+    --
+    -- See /Categories for the working mathematician/, Saunders Mac Lane, P.46.
+    data CommaCategory c1 m1 o1 c2 m2 o2 c3 m3 o3 = CommaCategory {leftDiag :: Diagram c1 m1 o1 c3 m3 o3 -- ^ /T/
+                                                                , rightDiag :: Diagram c2 m2 o2 c3 m3 o3} -- ^ /S/
+                                                    deriving (Eq, Show)
+        
+    instance (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1,
+              FiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2,
+              FiniteCategory c3 m3 o3, Morphism m3 o3, Eq m3) => FiniteCategory (CommaCategory c1 m1 o1 c2 m2 o2 c3 m3 o3) (CommaMorphism o1 o2 m1 m2 m3) (CommaObject o1 o2 m3) where
+        ob CommaCategory {leftDiag = t, rightDiag = s} = [CommaObject{indexSrc=e,indexTgt=d,arrow=f}| e <- (ob (src t)), d <- (ob (src s)), f <- (ar (tgt t) ((omap t) !-! (e)) ((omap s) !-! (d)))]
+        identity CommaCategory{leftDiag = t, rightDiag = s} obj@CommaObject{indexSrc=e,indexTgt=d,arrow=f} 
+            = CommaMorphism{srcCM=obj, tgtCM=obj, indexAr1=(identity (src t) e), indexAr2=(identity (src s) d)}
+        ar CommaCategory{leftDiag = t, rightDiag = s} obj1@CommaObject{indexSrc=e1,indexTgt=d1,arrow=f1} obj2@CommaObject{indexSrc=e2,indexTgt=d2,arrow=f2}
+            = [CommaMorphism{srcCM=obj1,tgtCM=obj2,indexAr1=k,indexAr2=h}| k <- ar (src t) e1 e2, h <- ar (src s) d1 d2, f2 @ ((mmap t) !-! (k)) == ((mmap s) !-! (h)) @ f1]
+                    
+    instance (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1,
+              FiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2,
+              FiniteCategory c3 m3 o3, Morphism m3 o3, Eq m3) => GeneratedFiniteCategory (CommaCategory c1 m1 o1 c2 m2 o2 c3 m3 o3) (CommaMorphism o1 o2 m1 m2 m3) (CommaObject o1 o2 m3) where
+        genAr = defaultGenAr
+        decompose = defaultDecompose
+
+    instance (PrettyPrintable c1, PrettyPrintable m1, PrettyPrintable o1,
+              PrettyPrintable c2, PrettyPrintable m2, PrettyPrintable o2,
+              PrettyPrintable c3, PrettyPrintable m3, PrettyPrintable o3,
+              FiniteCategory c1 m1 o1, FiniteCategory c2 m2 o2, FiniteCategory c3 m3 o3,
+              Morphism m1 o1, Morphism m2 o2, Morphism m3 o3,
+              Eq m1, Eq o1, Eq m2, Eq o2) =>
+              PrettyPrintable (CommaCategory c1 m1 o1 c2 m2 o2 c3 m3 o3) where
+        pprint CommaCategory{leftDiag=t, rightDiag=s} = "("++pprint t++"|"++pprint s++")"
+
+    -- | Constructs the slice category of a category /C/ over an object /o/.
+    --
+    -- Returns Nothing if the object is not in the category.
+    mkSliceCategory :: (FiniteCategory c m o, Morphism m o, Eq o) => c -> o -> Maybe (CommaCategory c m o One One One c m o)
+    mkSliceCategory c o = mkSelect1 c o >>= (\x -> Just CommaCategory{leftDiag=mkIdentityDiagram c, rightDiag=x})
+        
+    -- | Constructs the coslice category of a category /C/ under an object /o/.
+    --
+    -- Returns Nothing if the object is not in the category.
+    mkCosliceCategory :: (FiniteCategory c m o, Morphism m o, Eq o) => c -> o -> Maybe (CommaCategory One One One c m o c m o)
+    mkCosliceCategory c o = mkSelect1 c o >>= (\x -> Just CommaCategory{rightDiag=mkIdentityDiagram c, leftDiag=x})
+        
+    -- | Constructs the arrow category of a category /C/.
+    mkArrowCategory :: (FiniteCategory c m o, Morphism m o, Eq o) => c -> CommaCategory c m o c m o c m o
+    mkArrowCategory c = CommaCategory{leftDiag=mkIdentityDiagram c, rightDiag=mkIdentityDiagram c}
+ src/CompositionGraph/CompositionGraph.hs view
@@ -0,0 +1,445 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
+
+{-| Module  : FiniteCategories
+Description : Composition graphs are the simpliest way to create simple small categories by hand.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+A `CompositionGraph` is the free category generated by a multidigraph quotiented by an equivalence relation on the paths of the graphs.
+A multidigraph is a directed multigraph which means that edges are oriented and there can be multiple arrows between two objects.
+
+The underlying multidigraph is given by a list of nodes and a list of arrows.
+
+The equivalence relation is given by a function on paths of the inductive graph.
+
+The function `mkCompositionGraph` checks the structure of the category and is the preferred way of instantiatiating the `CompositionGraph` type.
+If the check takes too long because the category is big, you can use the `CompositionGraph` if you're sure that the category structure is respected.
+
+Morphisms from different composition graphs should not be composed or compared, if they are, the behavior is undefined.
+
+When taking subcategories of a composition graph, the composition law might lead to morphisms not existing anymore.
+It is not a problem because they are equivalent, it is only counterintuitive for human readability.
+
+Example.ExampleCompositionGraph provides an example of composition graph construction.    
+-}
+
+
+module CompositionGraph.CompositionGraph 
+(
+    -- * Types for a graph
+    Arrow(..),
+    Graph(..),
+    -- * Types for a morphism of composition graph
+    RawPath(..),
+    Path(..),
+    CGMorphism(..),
+    -- * Types for a composition graph
+    CompositionLaw(..),
+    CompositionGraph(..),
+    -- * Construction
+    mkCompositionGraph,
+    mkEmptyCompositionGraph,
+    finiteCategoryToCompositionGraph,
+    generatedFiniteCategoryToCompositionGraph,
+    -- * Error gestion
+    CompositionGraphError(..),
+    -- * Insertion
+    insertObject,
+    insertMorphism,
+    -- * Modification
+    identifyMorphisms,
+    unidentifyMorphism,
+    replaceObject,
+    replaceMorphism,
+    -- * Deletion
+    deleteObject,
+    deleteMorphism,
+    -- * Utility functions
+    isGen,
+    isComp,
+    getLabel
+    
+)    
+where
+    import           Data.List                      ((\\), nub, intercalate, delete)
+    import           FiniteCategory.FiniteCategory
+    import           Utils.CartesianProduct         (cartesianProduct, (|^|))
+    import           Data.Maybe                     (isNothing, fromJust)
+    import           IO.PrettyPrint
+    import           Utils.AssociationList
+    import           Utils.Tuple
+    import           Diagram.Diagram
+    import           Config.Config
+    import           Cat.PartialFinCat
+    import           Control.Monad                  (foldM)
+        
+    -- | An `Arrow` is a source node, a target node and an identifier (for example a unique label).
+    type Arrow a b = (a, a, b)
+    
+    -- | A `RawPath` is a list of arrows.
+    type RawPath a b = [Arrow a b]
+    
+    -- | A `Path` is a `RawPath` with a source and a target specified.
+    --
+    -- An empty path is an identity in a free category. 
+    -- Therefore, it is useful to keep the source and the target when the path is empty
+    -- because there is one identity for each node of the graph. (We need to differentiate identites for each node.)
+    type Path a b = (a, RawPath a b, a)
+    
+    -- | A `CompositionLaw` is a `Data.Map` that maps raw paths to smaller raw paths in order to simplify paths
+    -- so that they don't compose infinitely many times when there is a cycle.
+    --
+    -- prop> length (law ! p) <= length p 
+    type CompositionLaw a b = AssociationList (RawPath a b) (RawPath a b)
+    
+    -- | The type `CGMorphism` is the type of composition graph morphisms.
+    --
+    -- It is a path with a composition law, it is necessary to keep the composition law of the composition graph
+    -- in every morphism of the graph because we need it to compose two morphisms and the morphisms compose 
+    -- independently of the composition graph.
+    data CGMorphism a b = CGMorphism {path :: Path a b, 
+                                      compositionLaw :: CompositionLaw a b} deriving (Show, Eq)
+    
+    instance (PrettyPrintable a, PrettyPrintable b, Eq a, Eq b) => PrettyPrintable (CGMorphism a b) where
+        pprint CGMorphism {path=(s,[],t),compositionLaw=cl} = if s == t then "Id"++(pprint s) else error "Identity with source different of target."
+        pprint CGMorphism {path=(_,rp,_),compositionLaw=cl} = intercalate " o " $ (\(_,_,l) -> pprint l) <$> rp
+                     
+    -- | A `Graph` is a list of nodes and a list of arrows.
+    type Graph a b = ([a],[Arrow a b])
+
+    -- | Helper function for `simplify`. Returns a simplified raw path.
+    simplifyOnce :: (Eq a, Eq b) => CompositionLaw a b -> RawPath a b -> RawPath a b
+    simplifyOnce _ [] = [] 
+    simplifyOnce _ [e] = [e]
+    simplifyOnce cl list 
+        | new_list == [] = []
+        | new_list /= list = new_list
+        | simple_tail /= (tail list) = (head list):simple_tail
+        | simple_init /= (init list) = simple_init++[(last list)]
+        | otherwise = list
+        where
+        new_list = (!-?) list list cl
+        simple_tail = simplifyOnce cl (tail list)
+        simple_init = simplifyOnce cl (init list)
+    
+    -- | Returns a completely simplified raw path.
+    simplify :: (Eq a, Eq b) => CompositionLaw a b -> RawPath a b -> RawPath a b
+    simplify _ [] = []
+    simplify cl rp 
+        | simple_one == rp = rp 
+        | otherwise = simplify cl simple_one 
+            where simple_one = simplifyOnce cl rp
+
+    instance (Eq a, Eq b) => Morphism (CGMorphism a b) a where
+        (@) CGMorphism{path=(s2,rp2,t2), compositionLaw=cl2} CGMorphism{path=(s1,rp1,t1), compositionLaw=cl1}
+            | t1 /= s2 = error "Composition of morphisms g@f where target of f is different of source of g"
+            | cl1 /= cl2 = error "Composition of morphisms with different composition laws"
+            | otherwise = CGMorphism{path=(s1,(simplify cl1 (rp2++rp1)),t2), compositionLaw=cl1}
+
+                                    
+        source CGMorphism{path=(s,_,_), compositionLaw=_} = s
+        target CGMorphism{path=(_,_,t), compositionLaw=_} = t
+                                    
+        
+    -- | Constructs a `CGMorphism` from a composition law and an arrow.
+    mkCGMorphism :: CompositionLaw a b -> Arrow a b -> CGMorphism a b
+    mkCGMorphism cl e@(s,t,l) = CGMorphism {path=(s,[e],t),compositionLaw=cl}
+
+    -- | Returns the list of arrows of a graph with a given source.
+    findOutwardEdges :: (Eq a) => Graph a b -> a -> [Arrow a b]
+    findOutwardEdges (nodes,edges) o = filter (\e@(s,t,_) -> s == o && elem t nodes) edges
+
+    -- | Returns the list of arrows of a graph with a given target.
+    findInwardEdges :: (Eq a) => Graph a b -> a -> [Arrow a b]
+    findInwardEdges (nodes,edges) o = filter (\e@(s,t,_) -> t == o && elem s nodes) edges
+    
+    -- | Constructs the identity associated to a node of a composition graph.
+    mkIdentity :: (Eq a) => Graph a b -> CompositionLaw a b -> a -> CGMorphism a b
+    mkIdentity g@(n,_) cl x 
+        | elem x n = CGMorphism {path=(x,[],x),compositionLaw=cl}
+        | otherwise = error ("Trying to construct identity of an unknown object.")
+
+    -- | Find all acyclic raw paths between two nodes in a graph.
+    findAcyclicRawPaths :: (Eq a) => Graph a b -> a -> a -> [RawPath a b]
+    findAcyclicRawPaths g s t = findAcyclicRawPathsVisitedNodes g s t [] where
+        findAcyclicRawPathsVisitedNodes g@(n,e) s t v
+            | elem t v = []
+            | s == t = [[]]
+            | otherwise = (concat (zipWith ($) (fmap fmap (fmap (:) inwardEdges)) (fmap (\x@(s1,t1,l1) -> (findAcyclicRawPathsVisitedNodes g s s1 (t:v))) inwardEdges))) where
+                            inwardEdges = (findInwardEdges g t) 
+    
+    -- | An elementary cycle is a cycle which is not composed of any other cycle.
+    findElementaryCycles :: (Eq a, Eq b) => Graph a b -> CompositionLaw a b -> a -> [RawPath a b]
+    findElementaryCycles g cl o = nub (simplify cl <$> []:(concat (zipWith sequence (fmap (fmap (\x y -> (y:x))) (fmap (\(s,_,_) ->  (findAcyclicRawPaths g o s)) inEdges)) inEdges))) where inEdges = (findInwardEdges g o)
+    
+    -- | Composes every elementary cycles of a node until they simplify into a fixed set of cycles.
+    --
+    -- Warning : this function can do an infinite loop if the composition law does not simplify a cycle or all of its child cycles.
+    -- We throw an error to stop this function when we reach a depth of 5.
+    findCycles :: (Eq a, Eq b) => Graph a b -> CompositionLaw a b -> a -> [RawPath a b]
+    findCycles g cl o = findCyclesWithPreviousCycles g cl o (findElementaryCycles g cl o) maximumLoopDepth where 
+        findCyclesWithPreviousCycles g cl o p n = if n == 0 then error "Suspected infinite loop because of a malformed composition graph." else if newCycles \\ p == [] then newCycles else (findCyclesWithPreviousCycles g cl o newCycles (n-1)) where
+            newCycles = nub ((simplify cl) <$> ((++) <$> p <*> findElementaryCycles g cl o))
+    
+    -- | Helper function which intertwine the second list in the first list.
+    --
+    -- Example : intertwine [1,2,3] [4,5] = [1,4,2,5,3]
+    intertwine :: [a] -> [a] -> [a]
+    intertwine [] l = l
+    intertwine l [] = l
+    intertwine l1@(x1:xs1) l2@(x2:xs2) = (x1:(x2:(intertwine xs1 xs2)))
+    
+    -- | Takes a path and intertwine every cycles possible along its path.
+    intertwineWithCycles :: (Eq a, Eq b) => Graph a b -> CompositionLaw a b -> a -> RawPath a b -> [RawPath a b]
+    intertwineWithCycles g cl _ p@(x@(_,t,_):xs) = (concat <$> sequence (fmap intertwine prodCycles) (fmap (:[]) p)) where
+        prodCycles = cartesianProduct cycles
+        cycles = (findCycles g cl t):((\(s,_,_) -> (findCycles g cl s)) <$> p)
+    intertwineWithCycles g cl s [] = (findCycles g cl s)
+        
+    -- | Enumerates all paths between two nodes and construct composition graph morphisms with them.
+    mkAr :: (Eq a, Eq b) => Graph a b -> CompositionLaw a b -> a -> a -> [CGMorphism a b]
+    mkAr g cl s t = (\p -> CGMorphism{path=(s,p,t),compositionLaw=cl}) <$> nub (simplify cl <$> concat((intertwineWithCycles g cl s) <$> acyclicPaths)) where
+        acyclicPaths = nub $ (simplify cl) <$> (findAcyclicRawPaths g s t)
+    
+    -- | A composition graph is a graph with a composition law. Use `mkCompositionGraph` to instantiate it unless it takes too long.
+    data CompositionGraph a b = CompositionGraph {graph :: Graph a b, law :: CompositionLaw a b} deriving (Eq, Show)
+    
+    instance (Eq a, Eq b) => FiniteCategory (CompositionGraph a b) (CGMorphism a b) a where
+        ob = fst.graph
+        identity c = mkIdentity (graph c) (law c)
+        ar c = mkAr (graph c) (law c)
+    
+    instance (Eq a, Eq b) => GeneratedFiniteCategory (CompositionGraph a b) (CGMorphism a b) a where
+        genAr c@CompositionGraph{graph=g,law=l} s t
+            | s == t = gen ++ [identity c s]
+            | otherwise = gen 
+            where gen = mkCGMorphism l <$> (filter (\a@(s1,t1,_) -> s == s1 && t == t1) $ snd g)
+            
+        decompose c m@CGMorphism{path=(_,rp,_),compositionLaw=l}
+            | isIdentity c m = [m]
+            | otherwise = mkCGMorphism l <$>  rp
+            
+    instance (PrettyPrintable a, PrettyPrintable b, Eq a, Eq b) => PrettyPrintable (CompositionGraph a b) where
+        pprint cg@CompositionGraph{graph=(nodes,arrs),law=_} = "CompositionGraph("++intercalate "," (pprint <$> nodes)++"\n"++intercalate "," ((\(a,b,c) -> pprint c ++ ":" ++ pprint a ++ "->" ++ pprint b) <$> arrs)        
+    
+    -- | Optimized version of isGenerator for `CompositionGraph`.
+    isGen :: (Eq a) => CGMorphism a b -> Bool
+    isGen m@CGMorphism{path=p@(s,rp,t),compositionLaw=_} = (length rp ) < 2
+    
+    -- | Optimized version of isComposite for `CompositionGraph`.
+    isComp :: (Eq a) => CGMorphism a b -> Bool
+    isComp = not.isGen
+    
+    -- | Returns the label of a generator arrow which is not an identity.
+    getLabel :: (Eq a) => CGMorphism a b -> Maybe b
+    getLabel CGMorphism{path=(_,[(_,_,label)],_),compositionLaw=_} = Just label
+    getLabel _ = Nothing
+            
+    -- | Constructs a `CompositionGraph` from a `Graph` and a `CompositionLaw`.
+    --
+    --  This is the preferred way of instantiating a `CompositionGraph` with `mkEmptyCompositionGraph`. This function checks the category structure,
+    --  that is why it can return a `FiniteCategoryError` if the graph and the composition law provided don't produce a valid category.
+    --  If this function takes too much time, use the `CompositionGraph` constructor at your own risk (it is your responsability to check the
+    --  the category structure is valid).
+    mkCompositionGraph :: (Eq a, Eq b, Show a) => Graph a b -> CompositionLaw a b -> Either (FiniteCategoryError (CGMorphism a b) a) (CompositionGraph a b) 
+    mkCompositionGraph g l
+        | isNothing check = Right c_g
+        | otherwise = Left (fromJust check)
+        where
+            c_g = CompositionGraph {graph = g, law = l}
+            check = checkGeneratedFiniteCategoryProperties c_g
+    
+    -- | Constructs an empty `CompositionGraph`.
+    --
+    -- Use `insertObject`, `insertMorphism` and `identifyMorphisms` to build a `CompositionGraph` from it.
+    mkEmptyCompositionGraph :: CompositionGraph a b
+    mkEmptyCompositionGraph = CompositionGraph {graph=([],[]), law=[]}
+    
+    
+    
+    -- | Transforms any `FiniteCategory` into a composition graph.
+    --
+    -- The composition graph will take more space in memory compared to the original category because the composition law is stored as a Data.Map.
+    --
+    -- Returns the `CompositionGraph` and an isofunctor as a `Diagram`.
+    finiteCategoryToCompositionGraph :: (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => c -> (CompositionGraph o m, Diagram c m o (CompositionGraph o m) (CGMorphism o m) o)
+    finiteCategoryToCompositionGraph cat = (cg,isofunct)
+        where
+            morphToArrow f = ((source f),(target f),f)
+            catLaw = [
+                if isNotIdentity cat (g @ f) then
+                    ([morphToArrow g,morphToArrow f],[morphToArrow (g @ f)])
+                else
+                    ([morphToArrow g,morphToArrow f],[]) |
+                f <- (arrows cat), g <- (arFrom cat (target f)), isNotIdentity cat f, isNotIdentity cat g]
+            cg = (CompositionGraph{graph=(ob cat, [morphToArrow f | f <- (arrows cat), isNotIdentity cat f])
+                                 , law= catLaw})
+            isofunct = Diagram{src=cat,tgt=cg,omap=functToAssocList id (ob cat),mmap=functToAssocList (\f -> if isNotIdentity cat f
+                                                                        then
+                                                                            mkCGMorphism catLaw (morphToArrow f)
+                                                                        else
+                                                                            identity cg (source f)) (arrows cat)}
+                                                                            
+    -- | Transforms any `GeneratedFiniteCategory` into a composition graph.
+    --
+    -- The composition graph will take more space in memory compared to the original category because the composition law is stored as a Data.Map.
+    --
+    -- Returns the `CompositionGraph` and an isofunctor as a `Diagram`.
+    generatedFiniteCategoryToCompositionGraph :: (GeneratedFiniteCategory c m o, Morphism m o, Eq m, Eq o) => c -> (CompositionGraph o m, Diagram c m o (CompositionGraph o m) (CGMorphism o m) o)
+    generatedFiniteCategoryToCompositionGraph cat = (cg,isofunct)
+        where
+            morphToArrow f = ((source f),(target f),f)
+            catLaw = [
+                if isNotIdentity cat (g @ f) then
+                    ((morphToArrow <$> (decompose cat g))++(morphToArrow <$> (decompose cat f)), morphToArrow <$> (decompose cat (g @ f)))
+                else
+                    ((morphToArrow <$> (decompose cat g))++(morphToArrow <$> (decompose cat f)),[]) |
+                f <- (arrows cat), g <- (arFrom cat (target f)), isNotIdentity cat f, isNotIdentity cat g]
+            cg = (CompositionGraph{graph=(ob cat, [morphToArrow f | f <- (genArrows cat), isNotIdentity cat f])
+                                 , law= catLaw})
+            isofunct = Diagram{src=cat,tgt=cg,omap=functToAssocList id (ob cat),mmap= functToAssocList (\f -> if isNotIdentity cat f
+                                                                        then
+                                                                            CGMorphism {path=(source f,(morphToArrow <$> (decompose cat f)),target f),compositionLaw=catLaw}
+                                                                        else
+                                                                            identity cg (source f)) (arrows cat)}
+    
+    -- | The datatype for composition graph construction errors.
+    data CompositionGraphError a b = InsertMorphismNonExistantSource {faultyMorph :: b, faultySrc :: a}
+                                   | InsertMorphismNonExistantTarget {faultyMorph :: b, faultyTgt :: a}
+                                   | IdentifyGenerator {gen :: CGMorphism a b}
+                                   | UnidentifyNonExistantMorphism {morph :: CGMorphism a b}
+                                   | ResultingCategoryError (FiniteCategoryError (CGMorphism a b) a)
+                                   | ReplaceNonExistantObject {faultyObj :: a}
+                                   | ReplaceCompositeMorphism {composite :: CGMorphism a b}
+                                   | DeleteIdentity {faultyIdentity :: CGMorphism a b}
+                                   | DeleteCompositeMorph {composite :: CGMorphism a b}
+                                   | DeleteNonExistantObjectMorph {neMorph :: CGMorphism a b}
+                                   | DeleteNonExistantObject {faultyObj :: a}
+    
+    -- | Inserts an object in a `CompositionGraph`, returns the new `CompositionGraph` and a `PartialFunctor` which is the insertion functor.
+    insertObject :: (Eq a, Eq b) => CompositionGraph a b -> a -> (CompositionGraph a b, (PartialFunctor (CompositionGraph a b) (CGMorphism a b) a))
+    insertObject prev@CompositionGraph{graph=(nodes,arrs), law=l} obj = (new, funct)
+        where
+            new = CompositionGraph{graph=(obj:nodes,arrs), law=l}
+            funct = PartialFunctor{srcPF=prev,tgtPF=new,omapPF=functToAssocList id nodes,mmapPF=functToAssocList id (arrows prev)}
+            
+    -- | Inserts a morphism in a `CompositionGraph`, returns the new `CompositionGraph` and a `PartialFunctor` which is the insertion functor if it can, returns Nothing otherwise.
+    --
+    -- This function fails if the two nodes provided as source and target for the new morphism are not both in the composition graph.
+    --
+    -- The result may not be a valid `CompositionGraph` (the new morphism might close a loop creating infinitely many morphisms).
+    -- You can use the function `identifyMorphisms` to transform it back into a valid `CompositionGraph`.
+    insertMorphism :: (Eq a, Eq b) => CompositionGraph a b -> a -> a -> b -> Either
+                                                                                (CompositionGraphError a b)
+                                                                                (CompositionGraph a b, (PartialFunctor (CompositionGraph a b) (CGMorphism a b) a))
+    insertMorphism prev@CompositionGraph{graph=(nodes,arrs), law=l} src tgt morph
+        | elem src nodes && elem tgt nodes = Right (new, funct)
+        | not $ elem src nodes = Left InsertMorphismNonExistantSource{faultyMorph=morph, faultySrc=src}
+        | not $ elem tgt nodes = Left InsertMorphismNonExistantTarget{faultyMorph=morph, faultyTgt=tgt}
+        where
+            new = CompositionGraph{graph=(nodes,(src, tgt, morph):arrs), law=l}
+            funct = PartialFunctor{srcPF=prev,tgtPF=new,omapPF=functToAssocList id nodes,mmapPF=functToAssocList id (arrows prev)}
+            
+    -- | Identify two morphisms if it is possible, if not returns an error in a Left member.
+    --
+    -- You can only identify a composite morphism to another morphism.
+    --
+    -- If the resulting composition graph is not associative, it returns Left CompositionNotAssociative.
+    identifyMorphisms :: (Eq a, Eq b) => CompositionGraph a b -> CGMorphism a b -> CGMorphism a b -> Either
+                                                                                                        (CompositionGraphError a b)
+                                                                                                        (CompositionGraph a b, (PartialFunctor (CompositionGraph a b) (CGMorphism a b) a))
+    identifyMorphisms prev@CompositionGraph{graph=(nodes,arrs), law=l} srcM tgtM
+        | isGen srcM = Left IdentifyGenerator{gen=srcM}
+        | isNothing check = Right (new,funct)
+        | otherwise = Left $ ResultingCategoryError (fromJust check)
+        where
+            newLaw = ((snd3.path) srcM,(snd3.path) tgtM):l
+            new = CompositionGraph{graph=(nodes,arrs), law=newLaw}
+            check = checkGeneratedFiniteCategoryProperties new
+            replaceLaw m = CGMorphism{path=(path m)
+                                     ,compositionLaw=newLaw}
+            funct = PartialFunctor{srcPF=prev,tgtPF=new,omapPF=functToAssocList id nodes,mmapPF=functToAssocList replaceLaw (delete srcM (arrows prev))}
+    
+    -- | Unidentify a morphism if it is possible, if not returns an error in a Left member.
+    --
+    -- Unidentifying a morphism means removing all entries in the composition law with results the morphism.    
+    unidentifyMorphism :: (Eq a, Eq b) => CompositionGraph a b -> CGMorphism a b -> Either
+                                                                                        (CompositionGraphError a b)
+                                                                                        (CompositionGraph a b, (PartialFunctor (CompositionGraph a b) (CGMorphism a b) a))
+    unidentifyMorphism prev@CompositionGraph{graph=(nodes,arrs), law=l} m
+        | elem m (ar prev (source m) (target m)) = Right (new,funct)
+        | otherwise = Left UnidentifyNonExistantMorphism{morph=m}
+        where
+            newLaw = filter (((snd3.path $ m)/=).snd) l
+            replaceLawInMorph CGMorphism{path=p,compositionLaw=_} = CGMorphism{path=p,compositionLaw=newLaw}
+            new = CompositionGraph{graph=(nodes,arrs), law=newLaw}
+            funct = PartialFunctor{srcPF=prev,tgtPF=new,omapPF=functToAssocList id nodes,mmapPF=functToAssocList replaceLawInMorph (arrows prev)}
+            
+    -- | Replaces an object with a new one, if the object to replace is not in the composition graph, returns Nothing.
+    --
+    -- It is different from deleting the object and inserting the new one because deleting an object deletes all leaving and coming arrows.
+    replaceObject :: (Eq a, Eq b) => CompositionGraph a b -> a -> a -> Either
+                                                                        (CompositionGraphError a b)
+                                                                        (CompositionGraph a b, (PartialFunctor (CompositionGraph a b) (CGMorphism a b) a))
+    replaceObject prev@CompositionGraph{graph=(nodes,arrs), law=l} prevObj newObj
+        | elem prevObj (ob prev) = Right (new,funct)
+        | otherwise = Left ReplaceNonExistantObject {faultyObj=prevObj}
+        where
+            replace x = if x == prevObj then newObj else x
+            replaceArr (s,t,a) = (replace s, replace t, a)
+            replaceLawEntry (k,v) = (replaceArr <$> k, replaceArr <$> v)
+            replaceCGMorph CGMorphism{path=(s,rp,t),compositionLaw=l} = CGMorphism{path=(replace s,replaceArr <$> rp,replace t),compositionLaw=replaceLawEntry <$> l}
+            new = CompositionGraph{graph=(replace <$> nodes,replaceArr <$> arrs), law=replaceLawEntry <$> l}
+            funct = PartialFunctor{srcPF=prev,tgtPF=new,omapPF=functToAssocList replace nodes,mmapPF=functToAssocList replaceCGMorph (arrows prev)}
+            
+    -- | Replaces a generating morphism with a new one, if the morphism to replace is not a generator of the composition graph, returns Nothing.
+    --
+    -- It is different from deleting the morphism and inserting the new one because deleting an object deletes related composition law entries.
+    replaceMorphism :: (Eq a, Eq b) => CompositionGraph a b -> CGMorphism a b -> b -> Either
+                                                                                        (CompositionGraphError a b)
+                                                                                        (CompositionGraph a b, (PartialFunctor (CompositionGraph a b) (CGMorphism a b) a))
+    replaceMorphism prev@CompositionGraph{graph=(nodes,arrs), law=l} prevMorph newMorph
+        | elem prevMorph (genAr prev (source prevMorph) (target prevMorph)) = Right (new,funct)
+        | otherwise = Left ReplaceCompositeMorphism{composite=prevMorph}
+        where
+            replaceArr m@(s,t,a) = if [m] == (snd3.path $ prevMorph) then (s, t, newMorph) else m
+            replaceLawEntry (k,v) = (replaceArr <$> k, replaceArr <$> v)
+            replaceCGMorph CGMorphism{path=(s,rp,t),compositionLaw=l} = CGMorphism{path=(s,replaceArr <$> rp,t),compositionLaw=replaceLawEntry <$> l}
+            new = CompositionGraph{graph=(nodes,replaceArr <$> arrs), law=replaceLawEntry <$> l}
+            funct = PartialFunctor{srcPF=prev,tgtPF=new,omapPF=functToAssocList id nodes,mmapPF=functToAssocList replaceCGMorph (arrows prev)}
+            
+    -- | Deletes a generating morphism if it can, the generator should not be an identity.
+    deleteMorphism :: (Eq a, Eq b) => CompositionGraph a b -> CGMorphism a b ->  Either
+                                                                                    (CompositionGraphError a b)
+                                                                                    (CompositionGraph a b, (PartialFunctor (CompositionGraph a b) (CGMorphism a b) a))
+    deleteMorphism prev@CompositionGraph{graph=(nodes,arrs), law=l} morph
+        | isIdentity prev morph = Left DeleteIdentity {faultyIdentity=morph}
+        | elem morph (genAr prev (source morph) (target morph)) = Right (new,funct)
+        | elem morph (ar prev (source morph) (target morph)) = Left DeleteCompositeMorph{composite=morph}
+        | otherwise = Left DeleteNonExistantObjectMorph{neMorph=morph}
+        where
+            arr = head.snd3.path $ morph
+            newLaw = filter (\(k,v) -> and ((/=arr) <$> k) && and ((/=arr) <$> v)) l
+            newArrows = filter (\CGMorphism{path=(s,rp,t),compositionLaw=_} -> not (elem arr rp)) (arrows prev)
+            replaceLaw m = CGMorphism{path=(path m)
+                                     ,compositionLaw=newLaw}
+            new = CompositionGraph{graph=(nodes,delete arr arrs), law=newLaw}
+            funct = PartialFunctor{srcPF=prev,tgtPF=new,omapPF=functToAssocList id nodes,mmapPF=functToAssocList replaceLaw newArrows}
+            
+    -- | Deletes an object and all morphism coming from it or leaving it.
+    deleteObject :: (Eq a, Eq b) => CompositionGraph a b -> a ->  Either
+                                                                    (CompositionGraphError a b)
+                                                                    (CompositionGraph a b, (PartialFunctor (CompositionGraph a b) (CGMorphism a b) a))
+    deleteObject prev@CompositionGraph{graph=(nodes,arrs), law=l} obj
+        | elem obj (ob prev) = (\(cg,f) -> (\(fcg,ffunct) -> (fcg,ffunct @ f)) (delObj cg)) <$> cgWithoutMorphs
+        | otherwise = Left DeleteNonExistantObject {faultyObj=obj}
+        where
+            idFunct = PartialFunctor{srcPF=prev,tgtPF=prev,omapPF=functToAssocList id nodes,mmapPF=functToAssocList id (arrows prev)}
+            cgWithoutMorphs = foldM (\(cg,f) d -> ((\(ncg,nf) -> (ncg,nf @ f)) <$> (deleteMorphism cg d))) (prev,idFunct) (filter (isNotIdentity prev) (nub ((genArFrom prev obj)++(genArTo prev obj))))
+            delObj prev2@CompositionGraph{graph=(nodes2,arrs2), law=l2} = (finalCG,
+                                                                           PartialFunctor{srcPF=prev2,tgtPF=finalCG,omapPF=functToAssocList id (delete obj nodes2),mmapPF=functToAssocList id ((arrows prev2)\\[(identity prev2 obj)])})
+                where
+                    finalCG = CompositionGraph{graph=(delete obj nodes2,arrs2), law=l2}
+ src/CompositionGraph/SafeCompositionGraph.hs view
@@ -0,0 +1,429 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
+
+{-| Module  : FiniteCategories
+Description : Composition graphs are the simpliest way to create simple small categories by hand.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+A `SafeCompositionGraph` is the quasi-free category generated by a multidigraph quotiented by an equivalence relation on the paths of the graphs. There is a limit on the number of cycles you can have in a morphism. It prevents any infinite loop from occuring.
+A multidigraph is a directed multigraph which means that edges are oriented and there can be multiple arrows between two objects.
+
+The underlying multidigraph is given by a list of nodes and a list of arrows.
+
+The equivalence relation is given by a function on paths of the inductive graph.
+
+The function `mkSafeCompositionGraph` checks the structure of the category and is the preferred way of instantiatiating the `SafeCompositionGraph` type.
+If the check takes too long because the category is big, you can use the `SafeCompositionGraph` constructor if you're sure that the category structure is respected.
+
+Morphisms from different composition graphs should not be composed or compared, if they are, the behavior is undefined.
+
+When taking subcategories of a composition graph, the composition law might lead to morphisms not existing anymore.
+It is not a problem because they are equivalent, it is only counterintuitive for human readability.
+
+Example.ExampleSafeCompositionGraph provides an example of composition graph construction.    
+-}
+
+
+module CompositionGraph.SafeCompositionGraph 
+(
+    -- * Types for a morphism of composition graph
+    SCGMorphism(..),
+    -- * Types for a composition graph
+    SafeCompositionGraph(..),
+    -- * Construction
+    mkSafeCompositionGraph,
+    mkEmptySafeCompositionGraph,
+    finiteCategoryToSafeCompositionGraph,
+    generatedFiniteCategoryToSafeCompositionGraph,
+    -- * Insertion
+    insertObjectS,
+    insertMorphismS,
+    -- * Modification
+    identifyMorphismsS,
+    unidentifyMorphismS,
+    replaceObjectS,
+    replaceMorphismS,
+    -- * Deletion
+    deleteObjectS,
+    deleteMorphismS,
+    -- * Utility functions
+    isGenS,
+    isCompS,
+    getLabelS
+    
+)    
+where
+    import           Data.List                      ((\\), nub, intercalate, delete)
+    import           FiniteCategory.FiniteCategory
+    import           Utils.CartesianProduct         (cartesianProduct, (|^|))
+    import           Data.Maybe                     (isNothing, fromJust)
+    import           IO.PrettyPrint
+    import           Utils.AssociationList
+    import           Utils.Tuple
+    import           Diagram.Diagram
+    import           Config.Config
+    import           Cat.PartialFinCat
+    import           Control.Monad                  (foldM)
+    import           CompositionGraph.CompositionGraph
+    
+    -- | The type `SCGMorphism` is the type of safe composition graph morphisms.
+    --
+    -- It is a path with a composition law, it is necessary to keep the composition law of the composition graph
+    -- in every morphism of the graph because we need it to compose two morphisms and the morphisms compose 
+    -- independently of the composition graph.
+    -- We also store the maximum number of cycles.
+    data SCGMorphism a b = SCGMorphism {pathS :: Path a b 
+                                       ,compositionLawS :: CompositionLaw a b
+                                       ,maxNbCycles :: Int} deriving (Show, Eq)
+    
+    instance (PrettyPrintable a, PrettyPrintable b, Eq a, Eq b) => PrettyPrintable (SCGMorphism a b) where
+        pprint SCGMorphism {pathS=(s,[],t),compositionLawS=_,maxNbCycles=_} = if s == t then "Id"++(pprint s) else error "Identity with source different of target."
+        pprint SCGMorphism {pathS=(_,rp,_),compositionLawS=_,maxNbCycles=_} = intercalate " o " $ (\(_,_,l) -> pprint l) <$> rp
+    
+    rawpathToListOfVertices :: RawPath a b -> [a]
+    rawpathToListOfVertices [] = []
+    rawpathToListOfVertices rp = ((snd3 (head rp)):(fst3 <$> rp))
+    
+    -- | Helper function for `simplify`. Returns a simplified raw path.
+    simplifyOnce :: (Eq a, Eq b) => CompositionLaw a b -> Int -> RawPath a b -> RawPath a b
+    simplifyOnce _ _ [] = [] 
+    simplifyOnce _ _ [e] = [e]
+    simplifyOnce cl nb list 
+        | new_list == [] = []
+        | isCycle && tooManyCycles = []
+        | new_list /= list = new_list
+        | simple_tail /= (tail list) = (head list):simple_tail
+        | simple_init /= (init list) = simple_init++[(last list)]
+        | otherwise = list
+        where
+        listOfVertices = rawpathToListOfVertices list
+        isCycle = (head listOfVertices) == (last listOfVertices)
+        tooManyCycles = (length $ filter ((head listOfVertices) ==) listOfVertices) == (nb+2)
+        new_list = (!-?) list list cl
+        simple_tail = simplifyOnce cl nb (tail list)
+        simple_init = simplifyOnce cl nb (init list)
+    
+    -- | Returns a completely simplified raw path.
+    simplify :: (Eq a, Eq b) => CompositionLaw a b -> Int -> RawPath a b -> RawPath a b
+    simplify _ _ [] = []
+    simplify cl nb rp 
+        | simple_one == rp = rp 
+        | otherwise = simplify cl nb simple_one 
+            where simple_one = simplifyOnce cl nb rp
+
+    instance (Eq a, Eq b) => Morphism (SCGMorphism a b) a where
+        (@) SCGMorphism{pathS=(s2,rp2,t2), compositionLawS=cl2, maxNbCycles=nb1} SCGMorphism{pathS=(s1,rp1,t1), compositionLawS=cl1, maxNbCycles=nb2}
+            | t1 /= s2 = error "Composition of morphisms g@f where target of f is different of source of g"
+            | cl1 /= cl2 = error "Composition of morphisms with different composition laws"
+            | nb1 /= nb2 = error "Composition of morphisms with different maximum number of cycles."
+            | otherwise = SCGMorphism{pathS=(s1,(simplify cl1 nb1 (rp2++rp1)),t2), compositionLawS=cl1, maxNbCycles=nb1}
+
+                                    
+        source SCGMorphism{pathS=(s,_,_), compositionLawS=_, maxNbCycles=_} = s
+        target SCGMorphism{pathS=(_,_,t), compositionLawS=_, maxNbCycles=_} = t
+                                    
+        
+    -- | Constructs a `SCGMorphism` from a composition law and an arrow.
+    mkSCGMorphism :: CompositionLaw a b -> Int -> Arrow a b -> SCGMorphism a b
+    mkSCGMorphism cl nb e@(s,t,l) = SCGMorphism {pathS=(s,[e],t),compositionLawS=cl, maxNbCycles=nb}
+
+    -- | Returns the list of arrows of a graph with a given source.
+    findOutwardEdges :: (Eq a) => Graph a b -> a -> [Arrow a b]
+    findOutwardEdges (nodes,edges) o = filter (\e@(s,t,_) -> s == o && elem t nodes) edges
+
+    -- | Returns the list of arrows of a graph with a given target.
+    findInwardEdges :: (Eq a) => Graph a b -> a -> [Arrow a b]
+    findInwardEdges (nodes,edges) o = filter (\e@(s,t,_) -> t == o && elem s nodes) edges
+    
+    -- | Constructs the identity associated to a node of a composition graph.
+    mkIdentity :: (Eq a) => Graph a b -> CompositionLaw a b -> Int -> a -> SCGMorphism a b
+    mkIdentity g@(n,_) cl nb x 
+        | elem x n = SCGMorphism {pathS=(x,[],x),compositionLawS=cl, maxNbCycles=nb}
+        | otherwise = error ("Trying to construct identity of an unknown object.")
+
+    -- | Find all acyclic raw paths between two nodes in a graph.
+    findAcyclicRawPaths :: (Eq a) => Graph a b -> a -> a -> [RawPath a b]
+    findAcyclicRawPaths g s t = findAcyclicRawPathsVisitedNodes g s t [] where
+        findAcyclicRawPathsVisitedNodes g@(n,e) s t v
+            | elem t v = []
+            | s == t = [[]]
+            | otherwise = (concat (zipWith ($) (fmap fmap (fmap (:) inwardEdges)) (fmap (\x@(s1,t1,l1) -> (findAcyclicRawPathsVisitedNodes g s s1 (t:v))) inwardEdges))) where
+                            inwardEdges = (findInwardEdges g t) 
+    
+    -- | An elementary cycle is a cycle which is not composed of any other cycle.
+    findElementaryCycles :: (Eq a, Eq b) => Graph a b -> CompositionLaw a b -> Int -> a -> [RawPath a b]
+    findElementaryCycles g cl nb o = nub (simplify cl nb <$> []:(concat (zipWith sequence (fmap (fmap (\x y -> (y:x))) (fmap (\(s,_,_) ->  (findAcyclicRawPaths g o s)) inEdges)) inEdges))) where inEdges = (findInwardEdges g o)
+    
+    -- | Composes every elementary cycles of a node until they simplify into a fixed set of cycles.
+    --
+    -- Warning : this function can do an infinite loop if the composition law does not simplify a cycle or all of its child cycles.
+    -- We throw an error to stop this function when we reach a depth of 5.
+    findCycles :: (Eq a, Eq b) => Graph a b -> CompositionLaw a b -> Int -> a -> [RawPath a b]
+    findCycles g cl nb o = findCyclesWithPreviousCycles g cl o (findElementaryCycles g cl nb o) where 
+        findCyclesWithPreviousCycles g cl o p = if newCycles \\ p == [] then newCycles else (findCyclesWithPreviousCycles g cl o newCycles) where
+            newCycles = nub ((simplify cl nb) <$> ((++) <$> p <*> findElementaryCycles g cl nb o))
+    
+    -- | Helper function which intertwine the second list in the first list.
+    --
+    -- Example : intertwine [1,2,3] [4,5] = [1,4,2,5,3]
+    intertwine :: [a] -> [a] -> [a]
+    intertwine [] l = l
+    intertwine l [] = l
+    intertwine l1@(x1:xs1) l2@(x2:xs2) = (x1:(x2:(intertwine xs1 xs2)))
+    
+    -- | Takes a path and intertwine every cycles possible along its path.
+    intertwineWithCycles :: (Eq a, Eq b) => Graph a b -> CompositionLaw a b -> Int -> a -> RawPath a b -> [RawPath a b]
+    intertwineWithCycles g cl nb _ p@(x@(_,t,_):xs) = (concat <$> sequence (fmap intertwine prodCycles) (fmap (:[]) p)) where
+        prodCycles = cartesianProduct cycles
+        cycles = (findCycles g cl nb t):((\(s,_,_) -> (findCycles g cl nb s)) <$> p)
+    intertwineWithCycles g cl nb s [] = (findCycles g cl nb s)
+        
+    -- | Enumerates all paths between two nodes and construct composition graph morphisms with them.
+    mkAr :: (Eq a, Eq b) => Graph a b -> CompositionLaw a b -> Int -> a -> a -> [SCGMorphism a b]
+    mkAr g cl nb s t = (\p -> SCGMorphism{pathS=(s,p,t),compositionLawS=cl,maxNbCycles=nb}) <$> nub (simplify cl nb <$> concat((intertwineWithCycles g cl nb s) <$> acyclicPaths)) where
+        acyclicPaths = nub $ (simplify cl nb) <$> (findAcyclicRawPaths g s t)
+    
+    -- | A composition graph is a graph with a composition law. Use `mkSafeCompositionGraph` to instantiate it unless it takes too long.
+    data SafeCompositionGraph a b = SafeCompositionGraph {graphS :: Graph a b, lawS :: CompositionLaw a b, maxCycles :: Int} deriving (Eq, Show)
+    
+    instance (Eq a, Eq b) => FiniteCategory (SafeCompositionGraph a b) (SCGMorphism a b) a where
+        ob = fst.graphS
+        identity c = mkIdentity (graphS c) (lawS c) (maxCycles c)
+        ar c = mkAr (graphS c) (lawS c) (maxCycles c)
+    
+    instance (Eq a, Eq b) => GeneratedFiniteCategory (SafeCompositionGraph a b) (SCGMorphism a b) a where
+        genAr c@SafeCompositionGraph{graphS=g,lawS=l,maxCycles=nb} s t
+            | s == t = gen ++ [identity c s]
+            | otherwise = gen 
+            where gen = mkSCGMorphism l nb <$> (filter (\a@(s1,t1,_) -> s == s1 && t == t1) $ snd g)
+            
+        decompose c m@SCGMorphism{pathS=(_,rp,_),compositionLawS=l,maxNbCycles=nb}
+            | isIdentity c m = [m]
+            | otherwise = mkSCGMorphism l nb <$>  rp
+            
+    instance (PrettyPrintable a, PrettyPrintable b, Eq a, Eq b) => PrettyPrintable (SafeCompositionGraph a b) where
+        pprint cg@SafeCompositionGraph{graphS=(nodes,arrs),lawS=_,maxCycles=_} = "SafeCompositionGraph("++intercalate "," (pprint <$> nodes)++"\n"++intercalate "," ((\(a,b,c) -> pprint c ++ ":" ++ pprint a ++ "->" ++ pprint b) <$> arrs)        
+    
+    -- | Optimized version of isGenerator for `SafeCompositionGraph`.
+    isGenS :: (Eq a) => SCGMorphism a b -> Bool
+    isGenS m@SCGMorphism{pathS=p@(s,rp,t),compositionLawS=_,maxNbCycles=_} = (length rp ) < 2
+    
+    -- | Optimized version of isComposite for `SafeCompositionGraph`.
+    isCompS :: (Eq a) => SCGMorphism a b -> Bool
+    isCompS = not.isGenS
+    
+    -- | Returns the label of a generator arrow which is not an identity.
+    getLabelS :: (Eq a) => SCGMorphism a b -> Maybe b
+    getLabelS SCGMorphism{pathS=(_,[(_,_,label)],_),compositionLawS=_,maxNbCycles=_} = Just label
+    getLabelS _ = Nothing
+            
+    -- | Constructs a `SafeCompositionGraph` from a `Graph` and a `CompositionLaw`.
+    --
+    --  This is the preferred way of instantiating a `SafeCompositionGraph` with `mkEmptySafeCompositionGraph`. This function checks the category structure,
+    --  that is why it can return a `FiniteCategoryError` if the graph and the composition law provided don't produce a valid category.
+    --  If this function takes too much time, use the `SafeCompositionGraph` constructor at your own risk (it is your responsability to check the
+    --  the category structure is valid).
+    mkSafeCompositionGraph :: (Eq a, Eq b, Show a) => Graph a b -> CompositionLaw a b -> Int -> Either (FiniteCategoryError (SCGMorphism a b) a) (SafeCompositionGraph a b) 
+    mkSafeCompositionGraph g l nb
+        | isNothing check = Right c_g
+        | otherwise = Left (fromJust check)
+        where
+            c_g = SafeCompositionGraph {graphS=g, lawS=l, maxCycles=nb}
+            check = checkGeneratedFiniteCategoryProperties c_g
+    
+    -- | Constructs an empty `SafeCompositionGraph` with a maximum number of cycles.
+    --
+    -- Use `insertObject`, `insertMorphism` and `identifyMorphisms` to build a `SafeCompositionGraph` from it.
+    mkEmptySafeCompositionGraph :: Int -> SafeCompositionGraph a b
+    mkEmptySafeCompositionGraph maxNbOfCycles = SafeCompositionGraph {graphS=([],[]), lawS=[], maxCycles=maxNbOfCycles}
+    
+    
+    
+    -- | Transforms any `FiniteCategory` into a safe composition graph.
+    --
+    -- The composition graph will take more space in memory compared to the original category because the composition law is stored as a Data.Map.
+    --
+    -- Returns the `SafeCompositionGraph` and an isofunctor as a `Diagram`.
+    finiteCategoryToSafeCompositionGraph :: (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => c -> (SafeCompositionGraph o m, Diagram c m o (SafeCompositionGraph o m) (SCGMorphism o m) o)
+    finiteCategoryToSafeCompositionGraph cat = (cg,isofunct)
+        where
+            maxnbcycles = maximum $ length <$> ((\x -> ar cat x x) <$> ob cat)  
+            morphToArrow f = ((source f),(target f),f)
+            catLaw = [
+                if isNotIdentity cat (g @ f) then
+                    ([morphToArrow g,morphToArrow f],[morphToArrow (g @ f)])
+                else
+                    ([morphToArrow g,morphToArrow f],[]) |
+                f <- (arrows cat), g <- (arFrom cat (target f)), isNotIdentity cat f, isNotIdentity cat g]
+            cg = (SafeCompositionGraph{graphS=(ob cat, [morphToArrow f | f <- (arrows cat), isNotIdentity cat f])
+                                 , lawS= catLaw, maxCycles=maxnbcycles})
+            isofunct = Diagram{src=cat,tgt=cg,omap=functToAssocList id (ob cat),mmap=functToAssocList (\f -> if isNotIdentity cat f
+                                                                        then
+                                                                            mkSCGMorphism catLaw maxnbcycles (morphToArrow f)
+                                                                        else
+                                                                            identity cg (source f)) (arrows cat)}
+                                                                            
+    -- | Transforms any `GeneratedFiniteCategory` into a safe composition graph.
+    --
+    -- The composition graph will take more space in memory compared to the original category because the composition law is stored as a Data.Map.
+    --
+    -- Returns the `SafeCompositionGraph` and an isofunctor as a `Diagram`.
+    generatedFiniteCategoryToSafeCompositionGraph :: (GeneratedFiniteCategory c m o, Morphism m o, Eq m, Eq o) => c -> (SafeCompositionGraph o m, Diagram c m o (SafeCompositionGraph o m) (SCGMorphism o m) o)
+    generatedFiniteCategoryToSafeCompositionGraph cat = (cg,isofunct)
+        where
+            maxnbcycles = maximum $ length <$> ((\x -> ar cat x x) <$> ob cat)
+            morphToArrow f = ((source f),(target f),f)
+            catLaw = [
+                if isNotIdentity cat (g @ f) then
+                    ((morphToArrow <$> (decompose cat g))++(morphToArrow <$> (decompose cat f)), morphToArrow <$> (decompose cat (g @ f)))
+                else
+                    ((morphToArrow <$> (decompose cat g))++(morphToArrow <$> (decompose cat f)),[]) |
+                f <- (arrows cat), g <- (arFrom cat (target f)), isNotIdentity cat f, isNotIdentity cat g]
+            cg = (SafeCompositionGraph{graphS=(ob cat, [morphToArrow f | f <- (genArrows cat), isNotIdentity cat f])
+                                 , lawS= catLaw, maxCycles=maxnbcycles})
+            isofunct = Diagram{src=cat,tgt=cg,omap=functToAssocList id (ob cat),mmap=functToAssocList (\f -> if isNotIdentity cat f
+                                                                        then
+                                                                            SCGMorphism {pathS=(source f,(morphToArrow <$> (decompose cat f)),target f),compositionLawS=catLaw, maxNbCycles=maxnbcycles}
+                                                                        else
+                                                                            identity cg (source f)) (arrows cat)}
+    
+    -- | Datatype representing how a safe composition graph might be malformed.
+    data SafeCompositionGraphError a b = InsertMorphismNonExistantSourceS {faultyMorphS :: b, faultySrcS :: a}
+                                   | InsertMorphismNonExistantTargetS {faultyMorphS :: b, faultyTgtS :: a}
+                                   | IdentifyGeneratorS {genS :: SCGMorphism a b}
+                                   | UnidentifyNonExistantMorphismS {morphS :: SCGMorphism a b}
+                                   | ResultingCategoryErrorS (FiniteCategoryError (SCGMorphism a b) a)
+                                   | ReplaceNonExistantObjectS {faultyObjS :: a}
+                                   | ReplaceCompositeMorphismS {compositeS :: SCGMorphism a b}
+                                   | DeleteIdentityS {faultyIdentityS :: SCGMorphism a b}
+                                   | DeleteCompositeMorphS {compositeS :: SCGMorphism a b}
+                                   | DeleteNonExistantObjectMorphS {neMorphS :: SCGMorphism a b}
+                                   | DeleteNonExistantObjectS {faultyObjS :: a}
+    
+    -- | Inserts an object in a `SafeCompositionGraph`, returns the new `SafeCompositionGraph` and a `PartialFunctor` which is the insertion functor.
+    insertObjectS :: (Eq a, Eq b) => SafeCompositionGraph a b -> a -> (SafeCompositionGraph a b, (PartialFunctor (SafeCompositionGraph a b) (SCGMorphism a b) a))
+    insertObjectS prev@SafeCompositionGraph{graphS=(nodes,arrs), lawS=l, maxCycles=nb} obj = (new, funct)
+        where
+            new = SafeCompositionGraph{graphS=(obj:nodes,arrs), lawS=l, maxCycles=nb}
+            funct = PartialFunctor{srcPF=prev,tgtPF=new,omapPF=functToAssocList id nodes,mmapPF=functToAssocList id (arrows prev)}
+            
+    -- | Inserts a morphism in a `SafeCompositionGraph`, returns the new `SafeCompositionGraph` and a `PartialFunctor` which is the insertion functor if it can, returns Nothing otherwise.
+    --
+    -- This function fails if the two nodes provided as source and target for the new morphism are not both in the composition graph.
+    --
+    -- The result may not be a valid `SafeCompositionGraph` (the new morphism might close a loop creating infinitely many morphisms).
+    -- You can use the function `identifyMorphisms` to transform it back into a valid `SafeCompositionGraph`.
+    insertMorphismS :: (Eq a, Eq b) => SafeCompositionGraph a b -> a -> a -> b -> Either
+                                                                                (SafeCompositionGraphError a b)
+                                                                                (SafeCompositionGraph a b, (PartialFunctor (SafeCompositionGraph a b) (SCGMorphism a b) a))
+    insertMorphismS prev@SafeCompositionGraph{graphS=(nodes,arrs), lawS=l, maxCycles=nb} src tgt morph
+        | elem src nodes && elem tgt nodes = Right (new, funct)
+        | not $ elem src nodes = Left InsertMorphismNonExistantSourceS{faultyMorphS=morph, faultySrcS=src}
+        | not $ elem tgt nodes = Left InsertMorphismNonExistantTargetS{faultyMorphS=morph, faultyTgtS=tgt}
+        where
+            new = SafeCompositionGraph{graphS=(nodes,(src, tgt, morph):arrs), lawS=l, maxCycles=nb}
+            funct = PartialFunctor{srcPF=prev,tgtPF=new,omapPF=functToAssocList id nodes,mmapPF=functToAssocList id (arrows prev)}
+            
+    -- | Identify two morphisms if it is possible, if not returns an error in a Left member.
+    --
+    -- You can only identify a composite morphism to another morphism.
+    --
+    -- If the resulting composition graph is not associative, it returns Left CompositionNotAssociative.
+    identifyMorphismsS :: (Eq a, Eq b) => SafeCompositionGraph a b -> SCGMorphism a b -> SCGMorphism a b -> Either
+                                                                                                        (SafeCompositionGraphError a b)
+                                                                                                        (SafeCompositionGraph a b, (PartialFunctor (SafeCompositionGraph a b) (SCGMorphism a b) a))
+    identifyMorphismsS prev@SafeCompositionGraph{graphS=(nodes,arrs), lawS=l, maxCycles=nb} srcM tgtM
+        | isGenS srcM = Left IdentifyGeneratorS{genS=srcM}
+        | isNothing check = Right (new,funct)
+        | otherwise = Left $ ResultingCategoryErrorS (fromJust check)
+        where
+            newLaw = ((snd3.pathS) srcM,(snd3.pathS) tgtM):l
+            new = SafeCompositionGraph{graphS=(nodes,arrs), lawS=newLaw, maxCycles=nb}
+            check = checkGeneratedFiniteCategoryProperties new
+            replaceLaw m = SCGMorphism{pathS=(pathS m)
+                                     ,compositionLawS=newLaw, maxNbCycles=nb}
+            funct = PartialFunctor{srcPF=prev,tgtPF=new,omapPF=functToAssocList id nodes,mmapPF=functToAssocList replaceLaw (delete srcM (arrows prev))}
+    
+    -- | Unidentify a morphism if it is possible, if not returns an error in a Left member.
+    --
+    -- Unidentifying a morphism means removing all entries in the composition law with results the morphism.    
+    unidentifyMorphismS :: (Eq a, Eq b) => SafeCompositionGraph a b -> SCGMorphism a b -> Either
+                                                                                        (SafeCompositionGraphError a b)
+                                                                                        (SafeCompositionGraph a b, (PartialFunctor (SafeCompositionGraph a b) (SCGMorphism a b) a))
+    unidentifyMorphismS prev@SafeCompositionGraph{graphS=(nodes,arrs), lawS=l, maxCycles=nb} m
+        | elem m (ar prev (source m) (target m)) = Right (new,funct)
+        | otherwise = Left UnidentifyNonExistantMorphismS{morphS=m}
+        where
+            newLaw = filter (((snd3.pathS $ m)/=).snd) l
+            replaceLawInMorph SCGMorphism{pathS=p,compositionLawS=_, maxNbCycles=_} = SCGMorphism{pathS=p,compositionLawS=newLaw, maxNbCycles=nb}
+            new = SafeCompositionGraph{graphS=(nodes,arrs), lawS=newLaw, maxCycles=nb}
+            funct = PartialFunctor{srcPF=prev,tgtPF=new,omapPF=functToAssocList id nodes,mmapPF=functToAssocList replaceLawInMorph (arrows prev)}
+            
+    -- | Replaces an object with a new one, if the object to replace is not in the composition graph, returns Nothing.
+    --
+    -- It is different from deleting the object and inserting the new one because deleting an object deletes all leaving and coming arrows.
+    replaceObjectS :: (Eq a, Eq b) => SafeCompositionGraph a b -> a -> a -> Either
+                                                                        (SafeCompositionGraphError a b)
+                                                                        (SafeCompositionGraph a b, (PartialFunctor (SafeCompositionGraph a b) (SCGMorphism a b) a))
+    replaceObjectS prev@SafeCompositionGraph{graphS=(nodes,arrs), lawS=l, maxCycles=nb} prevObj newObj
+        | elem prevObj (ob prev) = Right (new,funct)
+        | otherwise = Left ReplaceNonExistantObjectS {faultyObjS=prevObj}
+        where
+            replace x = if x == prevObj then newObj else x
+            replaceArr (s,t,a) = (replace s, replace t, a)
+            replaceLawEntry (k,v) = (replaceArr <$> k, replaceArr <$> v)
+            replaceCGMorph SCGMorphism{pathS=(s,rp,t),compositionLawS=l, maxNbCycles=nb} = SCGMorphism{pathS=(replace s,replaceArr <$> rp,replace t),compositionLawS=replaceLawEntry <$> l, maxNbCycles=nb}
+            new = SafeCompositionGraph{graphS=(replace <$> nodes,replaceArr <$> arrs), lawS=replaceLawEntry <$> l, maxCycles=nb}
+            funct = PartialFunctor{srcPF=prev,tgtPF=new,omapPF=functToAssocList replace nodes,mmapPF=functToAssocList replaceCGMorph (arrows prev)}
+            
+    -- | Replaces a generating morphism with a new one, if the morphism to replace is not a generator of the composition graph, returns Nothing.
+    --
+    -- It is different from deleting the morphism and inserting the new one because deleting an object deletes related composition law entries.
+    replaceMorphismS :: (Eq a, Eq b) => SafeCompositionGraph a b -> SCGMorphism a b -> b -> Either
+                                                                                        (SafeCompositionGraphError a b)
+                                                                                        (SafeCompositionGraph a b, (PartialFunctor (SafeCompositionGraph a b) (SCGMorphism a b) a))
+    replaceMorphismS prev@SafeCompositionGraph{graphS=(nodes,arrs), lawS=l, maxCycles=nb} prevMorph newMorph
+        | elem prevMorph (genAr prev (source prevMorph) (target prevMorph)) = Right (new,funct)
+        | otherwise = Left ReplaceCompositeMorphismS{compositeS=prevMorph}
+        where
+            replaceArr m@(s,t,a) = if [m] == (snd3.pathS $ prevMorph) then (s, t, newMorph) else m
+            replaceLawEntry (k,v) = (replaceArr <$> k, replaceArr <$> v)
+            replaceCGMorph SCGMorphism{pathS=(s,rp,t),compositionLawS=l, maxNbCycles=_} = SCGMorphism{pathS=(s,replaceArr <$> rp,t),compositionLawS=replaceLawEntry <$> l, maxNbCycles=nb}
+            new = SafeCompositionGraph{graphS=(nodes,replaceArr <$> arrs), lawS=replaceLawEntry <$> l, maxCycles=nb}
+            funct = PartialFunctor{srcPF=prev,tgtPF=new,omapPF=functToAssocList id nodes,mmapPF=functToAssocList replaceCGMorph (arrows prev)}
+            
+    -- | Deletes a generating morphism if it can, the generator should not be an identity.
+    deleteMorphismS :: (Eq a, Eq b) => SafeCompositionGraph a b -> SCGMorphism a b ->  Either
+                                                                                    (SafeCompositionGraphError a b)
+                                                                                    (SafeCompositionGraph a b, (PartialFunctor (SafeCompositionGraph a b) (SCGMorphism a b) a))
+    deleteMorphismS prev@SafeCompositionGraph{graphS=(nodes,arrs), lawS=l, maxCycles=nb} morph
+        | isIdentity prev morph = Left DeleteIdentityS {faultyIdentityS=morph}
+        | elem morph (genAr prev (source morph) (target morph)) = Right (new,funct)
+        | elem morph (ar prev (source morph) (target morph)) = Left DeleteCompositeMorphS{compositeS=morph}
+        | otherwise = Left DeleteNonExistantObjectMorphS{neMorphS=morph}
+        where
+            arr = head.snd3.pathS $ morph
+            newLaw = filter (\(k,v) -> and ((/=arr) <$> k) && and ((/=arr) <$> v)) l
+            newArrows = filter (\SCGMorphism{pathS=(s,rp,t),compositionLawS=_, maxNbCycles=_} -> not (elem arr rp)) (arrows prev)
+            replaceLaw m = SCGMorphism{pathS=(pathS m)
+                                     ,compositionLawS=newLaw,maxNbCycles=nb}
+            new = SafeCompositionGraph{graphS=(nodes,delete arr arrs), lawS=newLaw, maxCycles=nb}
+            funct = PartialFunctor{srcPF=prev,tgtPF=new,omapPF=functToAssocList id nodes,mmapPF=functToAssocList replaceLaw newArrows}
+            
+    -- | Deletes an object and all morphism coming from it or leaving it.
+    deleteObjectS :: (Eq a, Eq b) => SafeCompositionGraph a b -> a ->  Either
+                                                                    (SafeCompositionGraphError a b)
+                                                                    (SafeCompositionGraph a b, (PartialFunctor (SafeCompositionGraph a b) (SCGMorphism a b) a))
+    deleteObjectS prev@SafeCompositionGraph{graphS=(nodes,arrs), lawS=l, maxCycles=nb} obj
+        | elem obj (ob prev) = (\(cg,f) -> (\(fcg,ffunct) -> (fcg,ffunct @ f)) (delObj cg)) <$> cgWithoutMorphs
+        | otherwise = Left DeleteNonExistantObjectS {faultyObjS=obj}
+        where
+            idFunct = PartialFunctor{srcPF=prev,tgtPF=prev,omapPF=functToAssocList id nodes,mmapPF=functToAssocList id (arrows prev)}
+            cgWithoutMorphs = foldM (\(cg,f) d -> ((\(ncg,nf) -> (ncg,nf @ f)) <$> (deleteMorphismS cg d))) (prev,idFunct) (filter (isNotIdentity prev) (nub ((genArFrom prev obj)++(genArTo prev obj))))
+            delObj prev2@SafeCompositionGraph{graphS=(nodes2,arrs2), lawS=l2, maxCycles=nb} = (finalCG,
+                                                                           PartialFunctor{srcPF=prev2,tgtPF=finalCG,omapPF=functToAssocList id (delete obj nodes2),mmapPF=functToAssocList id ((arrows prev2)\\[(identity prev2 obj)])})
+                where
+                    finalCG = SafeCompositionGraph{graphS=(delete obj nodes2,arrs2), lawS=l2, maxCycles=nb}
+ src/ConeCategory/ConeCategory.hs view
@@ -0,0 +1,170 @@+{-# LANGUAGE MultiParamTypeClasses #-}
+
+{-| Module  : FiniteCategories
+Description : Category of cones and category of cocones of a diagram.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+A cone is an object in the comma category (/D/|1_/F/) where /D/ is the diagonal functor and 1_/F/ is the diagram that selects the diagram of interest in the functor category.
+
+A cocone is an object in the comma category (1_/F/|/D/).
+-}
+
+module ConeCategory.ConeCategory
+(
+    -- * Cone related functions and types.
+    Cone,
+    ConeMorphism,
+    ConeCategory,
+    apex,
+    coneToNaturalTransformation,
+    naturalTransformationToCone,
+    mkConeCategory,
+    conesOfApex,
+    terminalObjects,
+    limits,
+    -- * Cocone related functions and types.
+    Cocone,
+    CoconeMorphism,
+    CoconeCategory,
+    nadir,
+    coconeToNaturalTransformation,
+    naturalTransformationToCocone,
+    mkCoconeCategory,
+    coconesOfNadir,
+    initialObjects,
+    colimits
+)
+where
+    import FiniteCategory.FiniteCategory
+    import Diagram.Diagram
+    import DiagonalFunctor.DiagonalFunctor
+    import CommaCategory.CommaCategory
+    import FunctorCategory.FunctorCategory
+    import UsualCategories.One
+    import Data.Maybe                                  (fromJust)
+    import Utils.AssociationList
+
+    -- --------------------------------
+    -- Cone related functions and types.
+    -- --------------------------------
+        
+    -- | A `Cone` is a `CommaObject` in the `CommaCategory` (/D/|1_/F/).
+    type Cone c1 m1 o1 c2 m2 o2 = CommaObject o2 One (NaturalTransformation c1 m1 o1 c2 m2 o2)
+    
+    -- | A `ConeMorphism` is a morphism between cones.
+    type ConeMorphism c1 m1 o1 c2 m2 o2 = CommaMorphism o2 One m2 One (NaturalTransformation c1 m1 o1 c2 m2 o2)
+    
+    -- | `ConeCategory` is the type of the cone category, it is a `CommaCategory` (/D/|1_/F/).
+    type ConeCategory c1 m1 o1 c2 m2 o2 = CommaCategory c2 m2 o2 One One One (FunctorCategory c1 m1 o1 c2 m2 o2) (NaturalTransformation c1 m1 o1 c2 m2 o2) (Diagram c1 m1 o1 c2 m2 o2)
+
+    -- | Returns the `apex` of a `Cone`.
+    apex :: Cone c1 m1 o1 c2 m2 o2 -> o2
+    apex = indexSrc
+
+    -- | Returns the `Cone` as a `NaturalTransformation`.
+    --
+    -- prop> naturalTransformationToCone . coneToNaturalTransformation = id
+    -- prop> coneToNaturalTransformation . naturalTransformationToCone = id
+    coneToNaturalTransformation :: Cone c1 m1 o1 c2 m2 o2 -> NaturalTransformation c1 m1 o1 c2 m2 o2
+    coneToNaturalTransformation = arrow
+    
+    -- | Returns a `NaturalTransformation` as a `Cone`.
+    --
+    -- prop> naturalTransformationToCone . coneToNaturalTransformation = id
+    -- prop> coneToNaturalTransformation . naturalTransformationToCone = id
+    naturalTransformationToCone :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1
+                                   ,FiniteCategory c2 m2 o2, Morphism m2 o2) =>
+                                    NaturalTransformation c1 m1 o1 c2 m2 o2 -> Cone c1 m1 o1 c2 m2 o2
+    naturalTransformationToCone nt@NaturalTransformation{srcNT=s,tgtNT=t,component=compo}
+        | null (ob (src s)) = error "Cone of a diagram with empty index category"
+        | otherwise = CommaObject{indexSrc=(omap s) !-! (head (ob (src s))),indexTgt=One,arrow=nt}
+
+    -- | Constructs the category of cones of a diagram. Objects of the category are `CommaObject` objects with the `apex` of the cone in the `indexSrc` field and the natural transformation in the `arrow` field.
+    mkConeCategory :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq c1, Eq m1, Eq o1,
+                       FiniteCategory c2 m2 o2, Morphism m2 o2, Eq c2, Eq m2, Eq o2) =>
+                       Diagram c1 m1 o1 c2 m2 o2 -> ConeCategory c1 m1 o1 c2 m2 o2
+    mkConeCategory diag@Diagram{src=s,tgt=t,omap=om,mmap=fm} =  CommaCategory {leftDiag = diagonalFunct
+                                                                             , rightDiag = fromJust $ mkSelect1 (tgt diagonalFunct) diag}
+                                                                where
+                                                                    diagonalFunct = mkDiagonalFunctor s t
+
+    -- | Returns all cones of a given apex.
+    conesOfApex :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq c1, Eq m1, Eq o1,
+                    FiniteCategory c2 m2 o2, Morphism m2 o2, Eq c2, Eq m2, Eq o2) =>
+                       Diagram c1 m1 o1 c2 m2 o2 -> o2 -> [Cone c1 m1 o1 c2 m2 o2]
+    conesOfApex diag apx
+        | not $ elem apx (ob (tgt diag)) = error "Trying to construct cones from an apex not in the target category."
+        | otherwise = naturalTransformationToCone <$> ar functCat constDiag diag
+        where 
+            functCat = FunctorCategory (src diag) (tgt diag)
+            Just constDiag = mkConstantDiagram (src diag) (tgt diag) apx
+            
+    -- | Returns limits of a diagram (terminal cones).
+    limits :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq c1, Eq m1, Eq o1,
+               FiniteCategory c2 m2 o2, Morphism m2 o2, Eq c2, Eq m2, Eq o2) =>
+               Diagram c1 m1 o1 c2 m2 o2 -> [Cone c1 m1 o1 c2 m2 o2]
+    limits = terminalObjects.mkConeCategory
+    
+    -- --------------------------------
+    -- Cocone related functions and types.
+    -- --------------------------------
+    
+
+    -- | A `Cocone` is a `CommaObject` in the `CommaCategory` (1_/F/|/D/).
+    type Cocone c1 m1 o1 c2 m2 o2 = CommaObject One o2 (NaturalTransformation c1 m1 o1 c2 m2 o2)
+
+    -- | A `CoconeMorphism` is a morphism between cocones.
+    type CoconeMorphism c1 m1 o1 c2 m2 o2 = CommaMorphism One o2 One m2 (NaturalTransformation c1 m1 o1 c2 m2 o2)
+    
+    -- | `CoconeCategory` is the type of the cocone category, it is a `CommaCategory` (1_/F/|/D/).
+    type CoconeCategory c1 m1 o1 c2 m2 o2 = CommaCategory One One One c2 m2 o2 (FunctorCategory c1 m1 o1 c2 m2 o2) (NaturalTransformation c1 m1 o1 c2 m2 o2) (Diagram c1 m1 o1 c2 m2 o2)
+    
+    
+    -- | Returns the `nadir` of a `Cocone`.
+    nadir :: Cocone c1 m1 o1 c2 m2 o2 -> o2
+    nadir = indexTgt
+
+    -- | Returns the `Cocone` as a `NaturalTransformation`.
+    coconeToNaturalTransformation :: Cocone c1 m1 o1 c2 m2 o2 -> NaturalTransformation c1 m1 o1 c2 m2 o2
+    coconeToNaturalTransformation = arrow
+    
+    -- | Returns a `NaturalTransformation` as a `Cocone`.
+    --
+    -- prop> naturalTransformationToCocone . coconeToNaturalTransformation = id
+    -- prop> coconeToNaturalTransformation . naturalTransformationToCocone = id
+    naturalTransformationToCocone :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1
+                                     ,FiniteCategory c2 m2 o2, Morphism m2 o2) =>
+                                    NaturalTransformation c1 m1 o1 c2 m2 o2 -> Cocone c1 m1 o1 c2 m2 o2
+    naturalTransformationToCocone nt@NaturalTransformation{srcNT=s,tgtNT=t,component=compo}
+        | null (ob (src t)) = error "Diagram with empty index category"
+        | otherwise = CommaObject{indexSrc=One,indexTgt=(omap t) !-! (head (ob (src t))),arrow=nt}
+ 
+    -- | Constructs the category of cocones of a diagram. Objects of the category are `CommaObject` objects with the nadir of the cone in the `indexTgt` field and the natural transformation in the `arrow` field.
+    mkCoconeCategory :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq c1, Eq m1, Eq o1,
+                       FiniteCategory c2 m2 o2, Morphism m2 o2, Eq c2, Eq m2, Eq o2) =>
+                       Diagram c1 m1 o1 c2 m2 o2 -> CoconeCategory c1 m1 o1 c2 m2 o2
+    mkCoconeCategory diag@Diagram{src=s,tgt=t,omap=om,mmap=fm} =  CommaCategory {leftDiag = fromJust $ mkSelect1 (tgt diagonalFunct) diag
+                                                                               , rightDiag = diagonalFunct}
+                                                                where
+                                                                    diagonalFunct = mkDiagonalFunctor s t
+
+    -- | Returns all cocones of a given nadir.
+    coconesOfNadir :: ( FiniteCategory c1 m1 o1, Morphism m1 o1, Eq c1, Eq m1, Eq o1,
+                        FiniteCategory c2 m2 o2, Morphism m2 o2, Eq c2, Eq m2, Eq o2) =>
+                       Diagram c1 m1 o1 c2 m2 o2 -> o2 -> [Cocone c1 m1 o1 c2 m2 o2]
+    coconesOfNadir diag nadr
+        | not $ elem nadr (ob (tgt diag)) = error "Trying to construct cocones to a nadir not in the target category."
+        | otherwise = naturalTransformationToCocone <$> ar functCat diag constDiag
+        where 
+            functCat = FunctorCategory (src diag) (tgt diag)
+            Just constDiag = mkConstantDiagram (src diag) (tgt diag) nadr
+            
+    -- | Returns colimits of a diagram (initial cocones).
+    colimits :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq c1, Eq m1, Eq o1,
+               FiniteCategory c2 m2 o2, Morphism m2 o2, Eq c2, Eq m2, Eq o2) =>
+               Diagram c1 m1 o1 c2 m2 o2 -> [Cocone c1 m1 o1 c2 m2 o2]
+    colimits = initialObjects.mkCoconeCategory
+ src/ConeCategory/LeftCone.hs view
@@ -0,0 +1,134 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
+
+{-| Module  : FiniteCategories
+Description : A left cone on I is I with another object called the cone point and a single morphism from the cone point to every other object of I. 
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+A left cone on I is I with another object called the cone point and a single morphism from the cone point to every other object of I.
+
+See Category Theory for the Sciences (2014) David I. Spivak for more details.
+
+An usual cone on C is then a functor from a left cone on I to C.
+-}
+
+module ConeCategory.LeftCone
+(
+    -- * Cone related functions and types.
+    LeftCone(..),
+    inclusionFunctor,
+    ConeCategory(..)
+)
+where
+    import FiniteCategory.FiniteCategory
+    import IO.PrettyPrint
+    import Diagram.Diagram
+    import FunctorCategory.FunctorCategory
+    import Utils.AssociationList
+    
+    -- | Object in a `LeftCone` category, either an original object or the cone point.
+    data LeftConeObject o =   OriginalObject o
+                            | ConePoint
+                            deriving (Eq, Show)
+    
+    instance (PrettyPrintable o) => PrettyPrintable (LeftConeObject o) where
+        pprint (OriginalObject o) = pprint o
+        pprint ConePoint = "Left cone point"
+    
+    -- | Morphism in a `LeftCone` category, it is either an original morphism, a cone leg or the cone point identity.
+    data LeftConeMorphism m o = OriginalMorphism m
+                              | ConeLeg o
+                              | ConePointIdentity
+                              deriving (Eq, Show)
+                                
+    instance (PrettyPrintable m, PrettyPrintable o) => PrettyPrintable (LeftConeMorphism m o) where
+        pprint (OriginalMorphism m) = pprint m
+        pprint (ConeLeg o) = "Leg "++(pprint o)
+        pprint ConePointIdentity = "Id Cone Point"
+        
+    instance (Morphism m o, Eq o) => Morphism (LeftConeMorphism m o) (LeftConeObject o) where
+        (@) (OriginalMorphism g) (OriginalMorphism f) = OriginalMorphism (g @ f)
+        (@) (ConeLeg _) (OriginalMorphism _) = error "Cannot compose an original morphism with a cone leg."
+        (@) ConePointIdentity (OriginalMorphism _) = error "Cannot compose an original morphism with a cone point identity."
+        (@) (OriginalMorphism f) (ConeLeg o)
+            | (source f) == o = (ConeLeg (target f))
+            | otherwise = error "Source of original morphism is not target of cone leg."
+        (@) (ConeLeg _) (ConeLeg _) = error "Cannot compose two cone legs."
+        (@) ConePointIdentity (ConeLeg _) = error "Cannot compose a cone leg with a cone point identity"
+        (@) (ConeLeg o) ConePointIdentity = ConeLeg o
+        (@) ConePointIdentity ConePointIdentity = ConePointIdentity
+
+                                    
+        source (OriginalMorphism m) = OriginalObject (source m)
+        source (ConeLeg _) = ConePoint
+        source ConePointIdentity = ConePoint
+        target (OriginalMorphism m) = OriginalObject (target m)
+        target (ConeLeg o) = OriginalObject o
+        target ConePointIdentity = ConePoint
+    
+    -- | The left cone category associated to a category.
+    data LeftCone c m o = LeftCone c deriving (Eq, Show)
+    
+    instance (PrettyPrintable c) => PrettyPrintable (LeftCone c m o) where
+        pprint (LeftCone cat) = "Left cone of "++pprint cat
+    
+    instance (FiniteCategory c m o, Morphism m o) => FiniteCategory (LeftCone c m o) (LeftConeMorphism m o) (LeftConeObject o) where
+        ob (LeftCone cat) = ConePoint: (OriginalObject <$> (ob cat))
+        
+        identity (LeftCone cat) (OriginalObject o) = OriginalMorphism (identity cat o)
+        identity (LeftCone cat) ConePoint = ConePointIdentity
+        
+        ar (LeftCone cat) (OriginalObject s) (OriginalObject t) = OriginalMorphism <$> ar cat s t
+        ar (LeftCone cat) (OriginalObject s) ConePoint = []
+        ar (LeftCone cat) ConePoint (OriginalObject t) = [ConeLeg t]
+        ar (LeftCone cat) ConePoint ConePoint = [ConePointIdentity]
+        
+    instance (GeneratedFiniteCategory c m o, Morphism m o) => GeneratedFiniteCategory (LeftCone c m o) (LeftConeMorphism m o) (LeftConeObject o) where
+        genAr (LeftCone cat) (OriginalObject s) (OriginalObject t) = OriginalMorphism <$> genAr cat s t
+        genAr (LeftCone cat) (OriginalObject s) ConePoint = []
+        genAr (LeftCone cat) ConePoint (OriginalObject t) = [ConeLeg t]
+        genAr (LeftCone cat) ConePoint ConePoint = [ConePointIdentity]
+        
+        decompose (LeftCone cat) (OriginalMorphism m) = OriginalMorphism <$> (decompose cat m)
+        decompose (LeftCone cat) (ConeLeg o) = [ConeLeg o]
+        decompose (LeftCone cat) ConePointIdentity = [ConePointIdentity]
+    
+    -- | Inclusion functor from a category to its left cone category.
+    inclusionFunctor :: (FiniteCategory c m o, Morphism m o) => LeftCone c m o -> Diagram c m o (LeftCone c m o) (LeftConeMorphism m o) (LeftConeObject o)
+    inclusionFunctor lc@(LeftCone cat) = Diagram{ src=cat
+                                                , tgt=lc
+                                                , omap=functToAssocList OriginalObject (ob cat)
+                                                , mmap=functToAssocList OriginalMorphism (arrows cat)
+                                                }
+    
+    -- | The category of cones defined according to the left cone definition.
+    --
+    -- It is less efficient than the `ConeCategory.ConeCategory` implementation. This is only defined for pedagogical purposes.
+    data ConeCategory c1 m1 o1 c2 m2 o2 =  ConeCategory (Diagram c1 m1 o1 c2 m2 o2) deriving (Eq, Show)
+    
+    instance (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq c1, Eq m1, Eq o1
+            , FiniteCategory c2 m2 o2, Morphism m2 o2, Eq c2, Eq m2, Eq o2) => FiniteCategory 
+        (ConeCategory c1 m1 o1 c2 m2 o2)
+        (NaturalTransformation (LeftCone c1 m1 o1) (LeftConeMorphism m1 o1) (LeftConeObject o1) c2 m2 o2)
+        (Diagram (LeftCone c1 m1 o1) (LeftConeMorphism m1 o1) (LeftConeObject o1) c2 m2 o2) where
+        ob (ConeCategory diag) = [s | s <- ob FunctorCategory{sourceCat = lcone, targetCat = tgt diag}, s `composeDiag` (inclusionFunctor lcone) == diag]
+            where lcone = LeftCone (src diag)
+        
+        identity (ConeCategory diag) cone = identity FunctorCategory{sourceCat = LeftCone (src diag), targetCat = tgt diag} cone
+        
+        ar (ConeCategory diag) cone1 cone2 = [nt | nt <- ar functCat cone1 cone2, preWhiskering nt (inclusionFunctor lcone) == (identity functCatDiag diag)]
+            where 
+                lcone =  LeftCone (src diag)
+                functCat = FunctorCategory{sourceCat = lcone, targetCat = tgt diag}
+                functCatDiag = FunctorCategory{sourceCat = src diag, targetCat = tgt diag}
+        
+    instance (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq c1, Eq m1, Eq o1
+            , FiniteCategory c2 m2 o2, Morphism m2 o2, Eq c2, Eq m2, Eq o2) => GeneratedFiniteCategory 
+        (ConeCategory c1 m1 o1 c2 m2 o2)
+        (NaturalTransformation (LeftCone c1 m1 o1) (LeftConeMorphism m1 o1) (LeftConeObject o1) c2 m2 o2)
+        (Diagram (LeftCone c1 m1 o1) (LeftConeMorphism m1 o1) (LeftConeObject o1) c2 m2 o2) where
+        genAr (ConeCategory diag) cone1 cone2 = genAr FunctorCategory{sourceCat = LeftCone (src diag), targetCat = tgt diag} cone1 cone2
+        decompose (ConeCategory diag) cone = decompose FunctorCategory{sourceCat = LeftCone (src diag), targetCat = tgt diag} cone
+ src/Config/Config.hs view
@@ -0,0 +1,18 @@+{-| Module  : FiniteCategories
+Description : Arbitrary values you can change.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Arbitrary values you can change.
+-}
+
+module Config.Config
+(
+    maximumLoopDepth
+) where
+    -- | The maximum number of loops in a /CompositionGraph/ before it throws an error.
+    maximumLoopDepth = 10
+    
+ src/Currying/Currying.hs view
@@ -0,0 +1,78 @@+{-# LANGUAGE MultiParamTypeClasses  #-}
+
+{-| Module  : FiniteCategories
+Description : Currying a functor @(A x B) -> C@ yields a functor @A -> [B,C]@.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Currying a functor @(A x B) -> C@ yields a functor @A -> [B,C]@.
+-}
+module Currying.Currying
+(
+curryDiagram,
+uncurryDiagram,
+switchArg,
+)
+where
+    import FiniteCategory.FiniteCategory
+    import ProductCategory.ProductCategory
+    import FunctorCategory.FunctorCategory
+    import Diagram.Diagram
+    import Utils.AssociationList
+    
+    -- | Curry a functor @D : A x B -> C@ into a functor @D' : A -> [B,C]@.
+    curryDiagram :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1,
+                     FiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2,
+                     FiniteCategory c3 m3 o3, Morphism m3 o3) =>
+                     Diagram (ProductCategory c1 m1 o1 c2 m2 o2) (ProductMorphism m1 o1 m2 o2) (ProductObject o1 o2) c3 m3 o3 -> Diagram c1 m1 o1 (FunctorCategory c2 m2 o2 c3 m3 o3) (NaturalTransformation c2 m2 o2 c3 m3 o3) (Diagram c2 m2 o2 c3 m3 o3)
+    curryDiagram diag = Diagram{ 
+                            src = (firstCategory (src diag)),
+                            tgt = FunctorCategory{ sourceCat = (secondCategory (src diag)), targetCat = (tgt diag)},
+                            omap = [(a, diagFromA a) | a <- ob (firstCategory (src diag))],
+                            mmap = [(f, natFromF f) | f <- arrows (firstCategory (src diag))]
+                        }
+        where
+            diagFromA a = Diagram{
+                            src = (secondCategory (src diag)),
+                            tgt = (tgt diag),
+                            omap = [ (b, (omap diag) !-! (ProductObject a b) ) | b <- ob (secondCategory (src diag))],
+                            mmap = [ (g, (mmap diag) !-! (ProductMorphism (identity (firstCategory (src diag)) a) g) ) | g <- arrows (secondCategory (src diag))]
+                          }
+            natFromF f = NaturalTransformation{
+                            srcNT = (diagFromA (source f)),
+                            tgtNT = (diagFromA (target f)),
+                            component = (\b -> (mmap diag) !-! (ProductMorphism f (identity (secondCategory (src diag)) b)))
+                        }
+    
+    -- | Uncurry a functor @D : A -> [B,C]@ into a functor @D' : A x B -> C@.
+    uncurryDiagram :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1,
+                     FiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2,
+                     FiniteCategory c3 m3 o3, Morphism m3 o3) =>
+                     Diagram c1 m1 o1 (FunctorCategory c2 m2 o2 c3 m3 o3) (NaturalTransformation c2 m2 o2 c3 m3 o3) (Diagram c2 m2 o2 c3 m3 o3) -> Diagram (ProductCategory c1 m1 o1 c2 m2 o2) (ProductMorphism m1 o1 m2 o2) (ProductObject o1 o2) c3 m3 o3
+    uncurryDiagram diag = Diagram{ src = ProductCategory (src diag) (sourceCat.tgt $ diag),
+                                 tgt = (targetCat.tgt $ diag),
+                                 omap = [(ProductObject a b, (omap ((omap diag) !-! a)) !-! b ) | a <- (ob (src diag)), b <- (ob (sourceCat.tgt $ diag))],
+                                 mmap = [(ProductMorphism f g, ((mmap ((omap diag) !-! (target f))) !-! g) @ ((component ((mmap diag) !-! f)) (source g)) ) | f <- (arrows (src diag)), g <- (arrows (sourceCat.tgt $ diag))]
+        }
+        
+    -- | Switches argument of a diagram @D : A x B -> C@ to create a diagram @D' : B x A -> C@.
+    switch ::  (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1,
+                FiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2,
+                FiniteCategory c3 m3 o3, Morphism m3 o3) =>
+                Diagram (ProductCategory c1 m1 o1 c2 m2 o2) (ProductMorphism m1 o1 m2 o2) (ProductObject o1 o2) c3 m3 o3 -> Diagram (ProductCategory c2 m2 o2 c1 m1 o1) (ProductMorphism m2 o2 m1 o1) (ProductObject o2 o1) c3 m3 o3
+    switch diag = Diagram {
+                    src = (ProductCategory (secondCategory.src $ diag) (firstCategory.src $ diag)),
+                    tgt = (tgt diag),
+                    omap = [((ProductObject b a), (omap diag) !-! o) | o@(ProductObject a b) <- (ob.src $ diag)],
+                    mmap = [((ProductMorphism b a), (mmap diag) !-! o) | o@(ProductMorphism a b) <- (arrows.src $ diag)]
+        }
+        
+    -- | Switches argument of a curried diagram.
+    switchArg :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1,
+                  FiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2,
+                  FiniteCategory c3 m3 o3, Morphism m3 o3) =>
+                  Diagram c1 m1 o1 (FunctorCategory c2 m2 o2 c3 m3 o3) (NaturalTransformation c2 m2 o2 c3 m3 o3) (Diagram c2 m2 o2 c3 m3 o3) -> Diagram c2 m2 o2 (FunctorCategory c1 m1 o1 c3 m3 o3) (NaturalTransformation c1 m1 o1 c3 m3 o3) (Diagram c1 m1 o1 c3 m3 o3)
+    switchArg = curryDiagram.switch.uncurryDiagram
+ src/DiagonalFunctor/DiagonalFunctor.hs view
@@ -0,0 +1,36 @@+{-| Module  : FiniteCategories
+Description : Diagonal functor of an index category.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Let /J/ and /C/ be two categories, we consider the functor category /C/^/J/.
+The diagonal functor /D/ : /C/ -> /C/^/J/ maps each object /x/ of /C/ to the constant diagram /D_x/ from /J/ to /C/.
+It maps each morphism to the natural transformation between the two constant diagrams associated to the source and the target of the morphism.
+-}
+
+module DiagonalFunctor.DiagonalFunctor
+(
+mkDiagonalFunctor
+)
+where
+    import Diagram.Diagram
+    import FiniteCategory.FiniteCategory
+    import FunctorCategory.FunctorCategory
+    import Data.Maybe                              (fromJust)
+    import Utils.AssociationList
+    
+    -- | Given two categories /J/ and /C/, returns the diagonal functor /C/ -> /C/^/J/.
+    mkDiagonalFunctor :: (FiniteCategory c1 m1 o1, Morphism m1 o1,
+                         FiniteCategory c2 m2 o2, Morphism m2 o2, Eq o2) =>
+                        c1 -- ^ /J/
+                     -> c2 -- ^ /C/
+                     -> Diagram c2 m2 o2 (FunctorCategory c1 m1 o1 c2 m2 o2) (NaturalTransformation c1 m1 o1 c2 m2 o2) (Diagram c1 m1 o1 c2 m2 o2) -- ^ /D/ : /C/ -> /C/^/J/
+    mkDiagonalFunctor j c = Diagram{src=c
+                                  , tgt=FunctorCategory{sourceCat=j, targetCat=c}
+                                  , omap=functToAssocList (\o ->  constDiag o) (ob c)
+                                  , mmap=functToAssocList (\f -> NaturalTransformation{srcNT=constDiag (source f),tgtNT=constDiag (target f),component=(\x->f)}) (arrows c)}
+                            where
+                                constDiag obj = fromJust $ mkConstantDiagram j c obj
+ src/Diagram/Conversion.hs view
@@ -0,0 +1,61 @@+{-| Module  : FiniteCategories
+Description : Functions to convert all functor types.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Functions to convert all functor types.
+-}
+
+module Diagram.Conversion
+(
+    -- * Diagram to something
+    diagramToFinFunctor,
+    diagramToPartialFunctor,
+    -- * FinFunctor to something
+    finFunctorToDiagram,
+    finFunctorToPartialFunctor,
+    -- * PartialFunctor to something
+    partialFunctorToDiagram,
+    partialFunctorToFinFunctor
+)
+where
+    import FiniteCategory.FiniteCategory
+    import Diagram.Diagram
+    import Cat.FinCat
+    import Cat.PartialFinCat
+    import Utils.SetList
+    import Utils.AssociationList
+    
+    -- | Converts a homogeneous `Diagram` to a `FinFunctor`.
+    diagramToFinFunctor :: (FiniteCategory c m o, Morphism m o) => Diagram c m o c m o -> FinFunctor c m o
+    diagramToFinFunctor Diagram{src=s,tgt=t,omap=om,mmap=fm} = FinFunctor{srcF=s,tgtF=t,omapF=om,mmapF=fm}
+    
+    -- | Converts a homogeneous `Diagram` to a `PartialFunctor`
+    diagramToPartialFunctor :: (FiniteCategory c m o, Morphism m o) => Diagram c m o c m o -> PartialFunctor c m o
+    diagramToPartialFunctor Diagram{src=s,tgt=t,omap=om,mmap=fm} = PartialFunctor{srcPF=s,tgtPF=t,omapPF=om,mmapPF=fm}
+    
+    -- | Converts a `FinFunctor` into a `Diagram`.
+    --
+    -- A `FinFunctor` is a morphism of the `FinCat` category, it is a homogeneous FinFunctor. This functions casts it to a heterogeneous FinFunctor (i.e. a `Diagram`).
+    finFunctorToDiagram :: FinFunctor c m o -> Diagram c m o c m o
+    finFunctorToDiagram FinFunctor{srcF=s,tgtF=t,omapF=om,mmapF=fm} = Diagram {src=s,tgt=t,omap=om,mmap=fm}
+    
+    -- | Converts a total functor to a partial functor.
+    finFunctorToPartialFunctor :: (FiniteCategory c m o, Morphism m o) => (FinFunctor c m o) -> (PartialFunctor c m o)
+    finFunctorToPartialFunctor FinFunctor{srcF=s,tgtF=t,omapF=om,mmapF=fm} = PartialFunctor{srcPF=s,tgtPF=t,omapPF=om,mmapPF=fm}
+    
+    -- | Try to convert a `PartialFunctor` into a `Diagram` if it can (if it is total).
+    partialFunctorToDiagram :: (FiniteCategory c m o, Morphism m o, Eq m, Eq o, Show o, Show m) => PartialFunctor c m o -> Maybe (Diagram c m o c m o)
+    partialFunctorToDiagram x = finFunctorToDiagram <$> partialFunctorToFinFunctor x
+    
+    -- | Try to convert a partial functor to a total functor if it is possible.
+    partialFunctorToFinFunctor :: (FiniteCategory c m o, Morphism m o, Eq m, Eq o, Show o, Show m) => (PartialFunctor c m o) -> Maybe (FinFunctor c m o)
+    partialFunctorToFinFunctor PartialFunctor{srcPF=s,tgtPF=t,omapPF=om,mmapPF=fm}
+        | not ((keys om) `doubleInclusion` (ob s)) = error $ (show $ ob s) ++"," ++ (show $ keys om)--Nothing
+        | not ((keys fm) `doubleInclusion` (arrows s)) = error $ (show $ arrows s) ++"," ++ (show $ keys fm)--Nothing
+        | otherwise = Just FinFunctor{srcF=s,tgtF=t,omapF=om,mmapF=fm}
+        
+        
+ src/Diagram/Diagram.hs view
@@ -0,0 +1,229 @@+{-| Module  : FiniteCategories
+Description : Functions to create usual and arbitrary diagrams.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+A diagram is a heterogeneous FinFunctor, it is a shift of perspective : we view the functor not as a morphism of categories but as a selection in a category.
+ 
+By heterogeneous, we mean that the type of the source category may be different from the target category.
+ 
+To convert a `Diagram` into any other kind of functor, see @Diagram.Conversion@.
+
+To enumerate all diagrams between two categories, see the `ob` function of /FunctorCategory/.
+-}
+
+module Diagram.Diagram
+(
+    -- * Diagram typeclass and useful functions
+    Diagram(..),
+    checkFunctoriality,
+    completeMmap,
+    composeDiag,
+    objectImage,
+    -- * Constructors of diagrams
+    mkDiagram,
+    mkIdentityDiagram,
+    mkConstantDiagram,
+    mkDiscreteDiagram,
+    mkSelect0,
+    mkSelect1,
+    mkSelect2,
+    mkSelect3,
+    mkTriangle,
+    mkParallel,
+    mkV,
+    mkHat,
+)
+where
+    import Prelude                          hiding ((@))
+    import FiniteCategory.FiniteCategory
+    import Cat.FinCat
+    import Cat.PartialFinCat
+    import UsualCategories.DiscreteCategory
+    import UsualCategories.Zero
+    import UsualCategories.One
+    import qualified UsualCategories.Two   as Two
+    import qualified UsualCategories.Three as Three
+    import qualified UsualCategories.Parallel as Par
+    import qualified UsualCategories.V as V
+    import qualified UsualCategories.Hat as Hat
+    import Data.List (intercalate, nub)
+    import Utils.SetList
+    import Utils.AssociationList
+    import IO.PrettyPrint
+    import IO.Show
+    
+    -- | A diagram is a heterogeneous FinFunctor /F/, it is a shift of perspective : we view the FinFunctor not as a morphism of categories but as a selection in a category. It must obey the following rules :
+    --
+    -- prop> F (src f) = src (F f) 
+    -- prop> F (tgt f) = tgt (F f)
+    -- prop> F (f @ g) = F(f) @ F(g)
+    -- prop> F (identity a) = identity (F a)
+    --
+    -- Unlike /FinFunctor/, a `Diagram` can have a source category and a target category with different types.
+    --
+    -- Using constructor functions `mkDiagram`, `mkConstantDiagram`, `mkDiscreteDiagram`, `mkSelect0`, `mkSelect1`, `mkSelect2`, `mkSelect3`, `mkTriangle` and `mkParallel` 
+    -- is the safe way to instantiate a `Diagram` (FinFunctoriality is checked during construction).
+    -- 
+    -- Therefore, if you want to construct an arbitrary diagram, use the constructor function `mkDiagram` unless it is too long to check FinFunctoriality in which case
+    -- you should use the `Diagram` constructor. It is then your responsability to ensure the FinFunctoriality property is verified.
+    data Diagram c1 m1 o1 c2 m2 o2 = Diagram {src :: c1 -- ^ The source category of the `Diagram`
+                                            , tgt :: c2 -- ^ The target category of the `Diagram`
+                                            , omap :: AssociationList o1 o2 -- ^ The object map
+                                            , mmap :: AssociationList m1 m2} -- ^ The morphism map
+                                            deriving (Eq, Show)
+    
+    -- | Checks wether the properties of a Diagram are respected. Returns True if the diagram is well formed, else False.
+    checkFunctoriality :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1,
+                           FiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2) =>
+                          Diagram c1 m1 o1 c2 m2 o2 -> Bool
+    checkFunctoriality Diagram{src=s,tgt=t,omap=om,mmap=fm}
+        | not (foldr (&&) True imIdNotId) = False
+        | not (foldr (&&) True errFunct) = False
+        | otherwise = True
+        where
+            imIdNotId = [fm !-! (identity s a) == identity t (om !-! a) | a <- ob s]
+            errFunct = [fm !-! (g @ f) == (fm !-! g) @ (fm !-! f) | f <- (arrows s), g <- (arFrom s (target f))]
+    
+    instance (FiniteCategory c1 m1 o1, Morphism m1 o1, PrettyPrintable m1, PrettyPrintable o1, Eq m1, Eq o1, PrettyPrintable c1,
+              FiniteCategory c2 m2 o2, Morphism m2 o2, PrettyPrintable m2, PrettyPrintable o2, PrettyPrintable c2) =>
+              PrettyPrintable (Diagram c1 m1 o1 c2 m2 o2) where
+        pprint Diagram{src=s,tgt=t,omap=om,mmap=fm} = "Diagram "++pprint s++" -> "++pprint t++"\n"++pprint om++"\n"++pprint fm
+    
+    -- | Constructor of an arbitrary `Diagram` that checks functoriality.
+    --
+    -- Use the `Diagram` constructor if the functoriality check is too slow. It is then your responsability to ensure the functoriality property is verified.
+    mkDiagram :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1,
+                  FiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2) =>
+                  c1 -- ^ The source category of the diagram.
+               -> c2 -- ^ The target category of the diagram.
+               -> AssociationList o1 o2 -- ^ The object map of the diagram.
+               -> AssociationList m1 m2 -- ^ The morphism map of the diagram.
+               -> Maybe (Diagram c1 m1 o1 c2 m2 o2) -- ^ The constructor returns Nothing if the FinFunctoriality check failed.
+    mkDiagram c1 c2 om fm = if checkFunctoriality diag then Just diag else Nothing
+        where diag = Diagram {src=c1, tgt=c2, omap=om, mmap=fm}
+    
+    -- | Completes the function map `mmap` of a diagram so that you do not have to specify images of identites and composite arrows.
+    completeMmap :: (GeneratedFiniteCategory c1 m1 o1, Morphism m1 o1, Eq o1, Eq m1,
+                              FiniteCategory c2 m2 o2, Morphism m2 o2, Eq o2, Eq m2) =>
+                       c1 -- ^ The source category, it must be a generated category. 
+                    -> c2 -- ^ The target category. 
+                    -> AssociationList o1 o2 -- ^ The omap. 
+                    -> AssociationList m1 m2 -- ^ The mmap to complete. 
+                    -> AssociationList m1 m2 -- ^ The completed mmap.
+    completeMmap c1 c2 om fm = nub fm2
+        where
+            fm1 = [(identity c1 o, identity c2 (om !-! o)) | o <- ob c1]++fm
+            fm2 = [(a,compose $ (fm1 !-!) <$> decompose c1 a) | a <- arrows c1]++fm1
+            
+    -- | Compose two diagrams.
+    composeDiag :: (FiniteCategory c1 m1 o1, Morphism m1 o1
+           ,FiniteCategory c2 m2 o2, Morphism m2 o2
+           ,FiniteCategory c3 m3 o3, Morphism m3 o3
+           ,Eq m1, Eq o1, Eq m2, Eq o2) => 
+           Diagram c2 m2 o2 c3 m3 o3 -> Diagram c1 m1 o1 c2 m2 o2 -> Diagram c1 m1 o1 c3 m3 o3
+    diag2 `composeDiag` diag1 = Diagram {src=(src diag1), tgt=(tgt diag2), omap=((omap diag2)!-.(omap diag1)), mmap=((mmap diag2)!-.(mmap diag1))} 
+    
+    -- | Returns the objects image of the diagram.
+    objectImage :: (FiniteCategory c1 m1 o1, Morphism m1 o1
+                   ,FiniteCategory c2 m2 o2, Morphism m2 o2) =>
+                    Diagram c1 m1 o1 c2 m2 o2 -> [o2]
+    objectImage diag = snd <$> (omap diag)
+    
+    -- | Constructs a diagram which maps a category to itself to that each object is mapped to itself and each morphism is mapped to itself too.
+    mkIdentityDiagram :: (FiniteCategory c m o, Morphism m o) => c -> (Diagram c m o c m o)
+    mkIdentityDiagram c = Diagram {src=c, tgt=c, omap=functToAssocList id (ob c),mmap=functToAssocList id (arrows c)}
+    
+    -- | Constructs a diagram where every object is mapped to a single object and every morphism is mapped to the identity of this single object.
+    mkConstantDiagram :: (FiniteCategory c1 m1 o1, Morphism m1 o1,
+                          FiniteCategory c2 m2 o2, Morphism m2 o2, Eq o2) => c1 -> c2 -> o2 -> Maybe (Diagram c1 m1 o1 c2 m2 o2)
+    mkConstantDiagram c1 c2 o2
+        | elem o2 (ob c2) = Just Diagram {src=c1, tgt=c2, omap=functToAssocList (\x -> o2) (ob c1),mmap=functToAssocList (\x -> (identity c2 o2)) (arrows c1)}
+        | otherwise = Nothing
+    
+    -- | Constructs a diagram that selects a list of objects of a category.
+    mkDiscreteDiagram :: (FiniteCategory c m o, Morphism m o, Eq o) =>
+                          c -> [o] -> Maybe (Diagram (DiscreteCategory o) (DiscreteIdentity o) (DiscreteObject o) c m o)
+    mkDiscreteDiagram c objs
+        | objs `isIncludedIn` (ob c) = Just Diagram {src=DiscreteCategory objs, tgt=c, omap=functToAssocList (\(DiscreteObject o) -> o) (ob (DiscreteCategory objs)),mmap=functToAssocList (\(DiscreteIdentity o) -> (identity c o)) (arrows (DiscreteCategory objs))}
+        | otherwise = Nothing
+    
+    -- | Constructs a diagram that selects no object and no morphism.
+    mkSelect0 :: (FiniteCategory c m o, Morphism m o) => c -> Diagram Zero Zero Zero c m o
+    mkSelect0 c = Diagram {src=Zero, tgt=c, omap=[],mmap=[]}
+    
+    -- | Constructs a diagram that selects a single object and its identity.
+    mkSelect1 :: (FiniteCategory c m o, Morphism m o, Eq o) => c -> o -> Maybe (Diagram One One One c m o)
+    mkSelect1 c o
+        | elem o (ob c) = Just Diagram {src=One, tgt=c, omap=[(One,o)],mmap=[(One,(identity c o))]}
+        | otherwise = Nothing
+    
+    -- | Constructs a diagram that selects a single arrow.
+    mkSelect2 :: (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => c -> m -> Maybe (Diagram Two.Two Two.TwoAr Two.TwoOb c m o)
+    mkSelect2 c m 
+        | condition = Just Diagram {src=Two.Two, tgt=c, omap=om,mmap=(completeMmap Two.Two c om [(Two.F,m)])}
+        | otherwise = Nothing
+        where
+            condition = elem (source m) (ob c) && elem (target m) (ob c) && elem m (ar c (source m) (target m))
+            om = [(Two.A,source m),(Two.B,target m)]
+            
+    -- | Constructs a diagram that selects a triangle.
+    --
+    -- > B <-f- A
+    -- > |     /
+    -- > g   g\@f
+    -- > |  /
+    -- > v v 
+    -- > C
+    mkSelect3 :: (FiniteCategory c m o, Morphism m o, Eq o, Eq m) => c -- ^ The target category.
+                                                                  -> m -- ^ /f/
+                                                                  -> m -- ^ /g/
+                                                                  -> Maybe (Diagram Three.Three Three.ThreeAr Three.ThreeOb c m o)
+    mkSelect3 c f g
+        | condition = Just Diagram {src=Three.Three, tgt=c, omap=om,mmap=(completeMmap Three.Three c om [(Three.F,f),(Three.G,g)])}
+        | otherwise = Nothing
+        where
+            condition = obInCat && arInCat && (source g) == (target f)
+            obInCat =  elem (source f) (ob c) && elem (target f) (ob c) && elem (target g) (ob c)
+            arInCat = elem f (ar c (source f) (target f)) && elem g (ar c (source g) (target g))
+            om = [(Three.A,source f),(Three.B,target f),(Three.C,target g)]
+            
+    -- | Constructs a diagram that selects a triangle. (Alias for `mkSelect3`).
+    mkTriangle :: (FiniteCategory c m o, Morphism m o, Eq o, Eq m) => c -> m -> m -> Maybe (Diagram Three.Three Three.ThreeAr Three.ThreeOb c m o)
+    mkTriangle = mkSelect3
+    
+    -- | Constructs a diagram that selects two parallel arrows.
+    mkParallel :: (FiniteCategory c m o, Morphism m o, Eq o, Eq m) => c -> m -> m -> Maybe (Diagram Par.Parallel Par.ParallelAr Par.ParallelOb c m o)
+    mkParallel c f g
+        | condition = Just Diagram {src=Par.Parallel, tgt=c, omap=om,mmap=(completeMmap Par.Parallel c om [(Par.F,f),(Par.G,g)])}
+        | otherwise = Nothing
+        where
+            condition = obInCat && arInCat && (source f) == (source g) && (target f) == (target g)
+            obInCat =  elem (source f) (ob c) && elem (target f) (ob c)
+            arInCat = elem f (ar c (source f) (target f)) && elem g (ar c (source g) (target g))
+            om = [(Par.A,source f), (Par.B, target f)]
+           
+    -- | Constructs a diagram that selects a V.
+    mkV :: (FiniteCategory c m o, Morphism m o, Eq o, Eq m) => c -> m -> m -> Maybe (Diagram V.V V.VAr V.VOb c m o)
+    mkV c f g
+        | condition = Just Diagram {src=V.V, tgt=c, omap=om,mmap=(completeMmap V.V c om [(V.F,f),(V.G,g)])}
+        | otherwise = Nothing
+        where
+            condition = obInCat && arInCat && (target f) == (target g)
+            obInCat =  elem (source f) (ob c) && elem (target f) (ob c)
+            arInCat = elem f (ar c (source f) (target f)) && elem g (ar c (source g) (target g))
+            om = [(V.A,source f), (V.B, source g), (V.C, target g)]
+            
+    -- | Constructs a diagram that selects a Hat.
+    mkHat :: (FiniteCategory c m o, Morphism m o, Eq o, Eq m) => c -> m -> m -> Maybe (Diagram Hat.Hat Hat.HatAr Hat.HatOb c m o)
+    mkHat c f g
+        | condition = Just Diagram {src=Hat.Hat, tgt=c, omap=om,mmap=(completeMmap Hat.Hat c om [(Hat.F,f),(Hat.G,g)])}
+        | otherwise = Nothing
+        where
+            condition = obInCat && arInCat && (source f) == (source g)
+            obInCat =  elem (source f) (ob c) && elem (target f) (ob c)
+            arInCat = elem f (ar c (source f) (target f)) && elem g (ar c (source g) (target g))
+            om = [(Hat.A,source f), (Hat.B, target f), (Hat.C, target g)]
+ src/ExportGraphViz/ExportGraphViz.hs view
@@ -0,0 +1,400 @@+{-| Module  : FiniteCategories
+Description : Visualize categories with GraphViz.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+This module is a way of visualizing categories with GraphViz.
+
+See Example.ExampleCompositionGraph or Example.ExampleSet.
+-}
+
+module ExportGraphViz.ExportGraphViz
+(
+    -- * Visualize categories
+    categoryToGraph,
+    catToDot,
+    catToPdf,
+    genToDot,
+    genToPdf,
+    -- * Visualize diagrams
+    diagToDotCluster,
+    diagToPdfCluster,
+    diagToDot,
+    diagToPdf,
+    diagToDot2,
+    diagToPdf2,
+    -- * Visualize natural transformations
+    natToDot,
+    natToPdf,
+    -- * Visualize cones
+    coneToDot,
+    coneToPdf
+)
+where
+    import              FiniteCategory.FiniteCategory
+    import              Diagram.Diagram
+    import              FunctorCategory.FunctorCategory
+    import              Utils.AssociationList
+    import              ConeCategory.ConeCategory
+    import              Subcategories.FreeSubcategory
+
+    import              Data.List                                   (elemIndex,intercalate)
+    import qualified    Data.Text.Lazy                      as L    (pack)
+    import qualified    Data.Text.Lazy.IO                   as IO   (putStrLn)
+    import              IO.CreateAndWriteFile                       (createAndWriteFile)
+    import              IO.PrettyPrint
+    import              Data.Graph.Inductive.Graph                  (mkGraph, Node, Edge, LNode, LEdge)
+    import              Data.Graph.Inductive.PatriciaTree           (Gr)
+    import              Data.GraphViz                               (graphToDot, nonClusteredParams, fmtNode, fmtEdge, GraphvizParams(..), NodeCluster(..), blankParams,GraphID( Num ), Number(..))
+    import              Data.GraphViz.Attributes.Complete           (Label(StrLabel), Attribute(Label))
+    import              Data.Word                                   (Word8)
+    import              Data.GraphViz.Attributes                    (X11Color(..), color)
+    import              Data.GraphViz.Printing                      (renderDot, toDot)
+    import              Data.Maybe
+    
+    import              System.Process                              (callCommand)
+    
+    
+    objToNode :: (Eq o, FiniteCategory c m o) => c -> o -> Node
+    objToNode c o
+        | index == Nothing = error("Call objToNod on an object not in the category.")
+        | otherwise = i
+        where 
+            Just i = index
+            index = elemIndex o (ob c)
+
+    objToLNode :: (Eq o, PrettyPrintable o, FiniteCategory c m o) => c -> o -> LNode String
+    objToLNode c o = (objToNode c o, pprint o)
+    
+    arToEdge :: (Eq o, Morphism m o, FiniteCategory c m o) => c -> m -> Edge
+    arToEdge c m = ((objToNode c). source $ m, (objToNode c). target $ m)
+    
+    arToLEdge :: (Eq o, PrettyPrintable o, PrettyPrintable m, Morphism m o, FiniteCategory c m o) => c -> m -> LEdge String
+    arToLEdge c m = ((objToNode c). source $ m, (objToNode c). target $ m, pprint m)
+    
+    -- | Transforms a category to representation as an inductive graph.
+    categoryToGraph :: (Eq o, PrettyPrintable o, PrettyPrintable m, Morphism m o, FiniteCategory c m o) => c -> Gr String String
+    categoryToGraph c = mkGraph (objToLNode c <$> (ob c)) (arToLEdge c <$> (arrows c))
+    
+    dotToPdf :: IO () -> String -> IO ()
+    dotToPdf dot path = dot >> callCommand ("dot "++path++" -o "++path++".pdf -T pdf") 
+    
+    -- | Export a category with GraphViz. If the category is too large, use `genToDot` instead.
+    --
+    -- The black arrows are generating arrows, grey one are generated arrows.
+    catToDot :: (Eq o, PrettyPrintable o, PrettyPrintable m, Morphism m o, GeneratedFiniteCategory c m o) => c -> String -> IO ()
+    catToDot c path = createAndWriteFile path $ renderDot $ toDot dot_file where
+        dot_file = graphToDot nonClusteredParams { fmtNode= \(n,label)-> [Label (StrLabel (L.pack label))],
+                                                   fmtEdge= \(n1,n2,label)-> [Label (StrLabel (L.pack label)),
+                                                   if elem label generatorsLabels then color Black else color Gray80]} (categoryToGraph c)
+        generators = genArrows c
+        generatorsLabels = pprint <$> generators
+
+    -- | Export a category with GraphViz. If the category is too large, use `genToPdf` instead.
+    --
+    -- The black arrows are generating arrows, grey one are generated arrows.
+    catToPdf :: (Eq o, PrettyPrintable o, PrettyPrintable m, Morphism m o, GeneratedFiniteCategory c m o) => c -> String -> IO ()
+    catToPdf c path = dotToPdf (catToDot c path) path
+    
+    -- | Transforms a category into an inductive graph.
+    categoryToGeneratorGraph :: (Eq o, PrettyPrintable o, PrettyPrintable m, Morphism m o, GeneratedFiniteCategory c m o) => c -> Gr String String
+    categoryToGeneratorGraph c = mkGraph (objToLNode c <$> (ob c)) (arToLEdge c <$> (genArrows c))
+    
+    -- | Export the generator of a category with GraphViz. Use this when the category is to large to be fully exported.
+    genToDot :: (Eq o, PrettyPrintable o, PrettyPrintable m, Morphism m o, GeneratedFiniteCategory c m o) => c -> String -> IO ()
+    genToDot c path = createAndWriteFile path $ renderDot $ toDot dot_file where
+        dot_file = graphToDot nonClusteredParams { fmtNode= \(n,label)-> [Label (StrLabel (L.pack label))],
+                                                   fmtEdge= \(n1,n2,label)-> [Label (StrLabel (L.pack label))]} (categoryToGeneratorGraph c)
+
+    -- | Export the generator of a category with GraphViz. Use this when the category is to large to be fully exported.
+    genToPdf :: (Eq o, PrettyPrintable o, PrettyPrintable m, Morphism m o, GeneratedFiniteCategory c m o) => c -> String -> IO ()
+    genToPdf c path =  dotToPdf (genToDot c path) path
+    
+    -- __________________________________
+    -- __________________________________
+    --
+    -- Diagram representation with cluster of objects mapped together
+    -- __________________________________
+    -- __________________________________
+    
+
+    
+    -- | If the nodeif pair, then it is part of the source category, else it is part of the target category.
+    diagObjToNodeCluster :: (Eq o, FiniteCategory c m o) => c -> Bool -> o -> Node
+    diagObjToNodeCluster c b o
+        | index == Nothing = error("Call diagObjToNod on an object not in the category.")
+        | otherwise = if b then 2*i else 2*i+1
+        where 
+            Just i = index
+            index = elemIndex o (ob c)
+            
+    diagObjToLNodeCluster :: (Eq o, PrettyPrintable o, FiniteCategory c m o) => c -> Bool -> o -> LNode String
+    diagObjToLNodeCluster c b o = (diagObjToNodeCluster c b o, pprint o)
+    
+    diagArToEdgeCluster :: (Eq o, Morphism m o, FiniteCategory c m o) => c -> Bool -> m -> Edge
+    diagArToEdgeCluster c b m = ((diagObjToNodeCluster c b). source $ m, (diagObjToNodeCluster c b). target $ m)
+    
+    diagArToLEdgeCluster :: (Eq o, PrettyPrintable o, PrettyPrintable m, Morphism m o, FiniteCategory c m o) => c -> Bool -> m -> LEdge String
+    diagArToLEdgeCluster c b m = ((diagObjToNodeCluster c b). source $ m, (diagObjToNodeCluster c b). target $ m, pprint m)
+    
+    diagToGraphCluster :: (Eq c1, Eq o1, PrettyPrintable o1, PrettyPrintable m1, Morphism m1 o1, GeneratedFiniteCategory c1 m1 o1,
+                           Eq c2, Eq o2, PrettyPrintable o2, PrettyPrintable m2, Morphism m2 o2, GeneratedFiniteCategory c2 m2 o2) =>
+                           Diagram c1 m1 o1 c2 m2 o2 -> Gr String String
+    diagToGraphCluster f = mkGraph ((diagObjToLNodeCluster (src f) True <$> (ob (src f)))++(diagObjToLNodeCluster (tgt f) False <$> (ob (tgt f)))) ((diagArToLEdgeCluster (src f) True <$> (genArrows (src f)))++(diagArToLEdgeCluster (tgt f) False <$> (genArrows (tgt f))))
+    
+    -- | Export a functor with GraphViz such that the source category is in green, the target in blue, the objects mapped together are in the same cluster.
+    diagToDotCluster :: (Eq c1, Eq o1, PrettyPrintable o1, PrettyPrintable m1, Morphism m1 o1, GeneratedFiniteCategory c1 m1 o1,
+                         Eq c2, Eq o2, PrettyPrintable o2, PrettyPrintable m2, Morphism m2 o2, GeneratedFiniteCategory c2 m2 o2) =>
+                        Diagram c1 m1 o1 c2 m2 o2 -> String -> IO ()
+    diagToDotCluster f@Diagram{src=s,tgt=t,omap=om,mmap=fm} path =  createAndWriteFile path $ renderDot $ toDot dot_file where
+        dot_file = graphToDot Params {
+                                             isDirected = True
+                                            ,globalAttributes = []
+                                            ,clusterBy = (\(n,nl) -> if (n `mod` 2) == 0 then (C ((fromJust (elemIndex (om !-! ((ob s) !! (n `div` 2))) (ob t)))) $ N (n,nl)) else (C (fromJust (elemIndex ((ob t) !! (n `div` 2)) (ob t))) $ N (n,nl)))
+                                            ,isDotCluster = const True
+                                            ,clusterID = Num . Int
+                                            ,fmtCluster = const []
+                                            ,fmtNode = \(n,label)-> [Label (StrLabel (L.pack label)), if (n `mod` 2) == 0 then color Green else color Blue]
+                                            ,fmtEdge= \(n1,n2,label)-> [Label (StrLabel (L.pack label))]
+                                          } (diagToGraphCluster f)
+    
+    -- | Export a functor as a pdf with GraphViz such that the source category is in green, the target in blue, the objects mapped together are in the same cluster.
+    diagToPdfCluster :: (Eq c1, Eq o1, PrettyPrintable o1, PrettyPrintable m1, Morphism m1 o1, GeneratedFiniteCategory c1 m1 o1,
+                         Eq c2, Eq o2, PrettyPrintable o2, PrettyPrintable m2, Morphism m2 o2, GeneratedFiniteCategory c2 m2 o2) =>
+                        Diagram c1 m1 o1 c2 m2 o2 -> String -> IO ()
+    diagToPdfCluster f path =  dotToPdf (diagToDotCluster f path) path
+    
+    -- __________________________________
+    -- __________________________________
+    --
+    -- Diagram representation with arrows between arrows
+    -- __________________________________
+    -- __________________________________
+    
+    indexAr :: (Morphism m o, FiniteCategory c m o, Eq o, Eq m) => c -> m -> Int
+    indexAr c m 
+        | elem m (arrows c) = fromJust $ elemIndex m (arrows c)
+        | otherwise = error "indexAr of arrow not in category"
+    
+    indexOb :: (FiniteCategory c m o, Eq o) => c -> o -> Int
+    indexOb c o
+        | elem o (ob c) = fromJust $ elemIndex o (ob c)
+        | otherwise = error "indexOb of object not in category"
+    
+    -- | If the node%4 == 0, then it is part of the source category, else if node%4 == 1 it is part of the target category.
+    diagObjToNode :: (Eq o, FiniteCategory c m o) => c -> Bool -> o -> Node
+    diagObjToNode c b o
+        | index == Nothing = error("Call diagObjToNode on an object not in the category.")
+        | otherwise = if b then 4*i else 4*i+1
+        where 
+            Just i = index
+            index = elemIndex o (ob c)
+    
+    diagObjToLNode :: (Eq o, PrettyPrintable o, FiniteCategory c m o) => c -> Bool -> o -> LNode String
+    diagObjToLNode c b o = (diagObjToNode c b o, pprint o)
+            
+    -- Creates the invisible node associated to an arrow of the source category if the boolean is True, of the target category if the boolean is False.
+    invisNodeSrc :: (Morphism m1 o1, FiniteCategory c1 m1 o1, Eq o1, Eq m1, PrettyPrintable m1,
+                     Morphism m2 o2, FiniteCategory c2 m2 o2, Eq o2, Eq m2, PrettyPrintable m2) =>
+                    (Diagram c1 m1 o1 c2 m2 o2) -> m1 -> LNode String
+    invisNodeSrc f@Diagram{src=s,tgt=t,mmap=_,omap=_} m = (4*(indexAr s m)+2, pprint m)
+    
+    invisNodeTgt :: (Morphism m1 o1, FiniteCategory c1 m1 o1, Eq o1, Eq m1, PrettyPrintable m1,
+                     Morphism m2 o2, FiniteCategory c2 m2 o2, Eq o2, Eq m2, PrettyPrintable m2) =>
+                    (Diagram c1 m1 o1 c2 m2 o2) -> m2 -> LNode String
+    invisNodeTgt f@Diagram{src=s,tgt=t,mmap=_,omap=_} m = (4*(indexAr t m)+3, pprint m)
+    
+    diagArToLEdges :: (Morphism m1 o1, FiniteCategory c1 m1 o1, Eq o1, Eq m1, PrettyPrintable m1,
+                       Morphism m2 o2, FiniteCategory c2 m2 o2, Eq o2, Eq m2, PrettyPrintable m2) =>
+                      (Diagram c1 m1 o1 c2 m2 o2) -> Either m1 m2 -> [LEdge String]
+    diagArToLEdges f@Diagram{src=s,tgt=t,omap=_,mmap=_} (Left m) = [((diagObjToNode s True). source $ m, fst.(invisNodeSrc f) $ m, ""),(fst.(invisNodeSrc f) $ m,(diagObjToNode s True). target $ m, "")]
+    diagArToLEdges f@Diagram{src=s,tgt=t,omap=_,mmap=_} (Right m) = [((diagObjToNode t False). source $ m, fst.(invisNodeTgt f) $ m, ""),(fst.(invisNodeTgt f) $ m,(diagObjToNode t False). target $ m, "")]
+    
+    linkArrows :: (Morphism m1 o1, FiniteCategory c1 m1 o1, Eq o1, Eq m1, PrettyPrintable m1,
+                   Morphism m2 o2, FiniteCategory c2 m2 o2, Eq o2, Eq m2, PrettyPrintable m2) =>
+                  (Diagram c1 m1 o1 c2 m2 o2) -> [LEdge String]
+    linkArrows f@Diagram{src=s,tgt=t,omap=_,mmap=fm} = (\m->(fst(invisNodeSrc f m),fst(invisNodeTgt f (fm !-! m)),"")) <$> (arrows s)
+    
+    linkObjects :: (Morphism m1 o1, FiniteCategory c1 m1 o1, Eq o1, Eq m1, PrettyPrintable m1,
+                    Morphism m2 o2, FiniteCategory c2 m2 o2, Eq o2, Eq m2, PrettyPrintable m2) =>
+                   (Diagram c1 m1 o1 c2 m2 o2) -> [LEdge String]
+    linkObjects f@Diagram{src=s,tgt=t,omap=om,mmap=_} = (\o->(diagObjToNode s True o,diagObjToNode t False (om !-! o),"")) <$> (ob s)
+    
+    diagToGraph :: (Morphism m1 o1, FiniteCategory c1 m1 o1, Eq o1, Eq m1, PrettyPrintable m1, PrettyPrintable o1,
+                    Morphism m2 o2, FiniteCategory c2 m2 o2, Eq o2, Eq m2, PrettyPrintable m2, PrettyPrintable o2) =>
+                   (Diagram c1 m1 o1 c2 m2 o2) -> Gr String String
+    diagToGraph f = mkGraph ((diagObjToLNode (src f) True <$> (ob (src f)))++(diagObjToLNode (tgt f) False <$> (ob (tgt f)))++((invisNodeSrc f) <$> (arrows (src f)))++((invisNodeTgt f) <$> (arrows (tgt f))))
+                             ((concat ((diagArToLEdges f <$> (Left <$> (arrows (src f))))++(diagArToLEdges f <$> (Right <$> (arrows (tgt f))))))++(linkArrows f)++(linkObjects f))
+    
+    -- | Export a diagram with GraphViz such that the source category is in green, the target in blue, each morphism is represented by a node.
+    diagToDot :: (Morphism m1 o1, FiniteCategory c1 m1 o1, Eq o1, Eq m1, PrettyPrintable m1, PrettyPrintable o1,
+                  Morphism m2 o2, FiniteCategory c2 m2 o2, Eq o2, Eq m2, PrettyPrintable m2, PrettyPrintable o2) =>
+                 (Diagram c1 m1 o1 c2 m2 o2) -> String -> IO ()
+    diagToDot f@Diagram{src=s,tgt=t,omap=om,mmap=fm} path =  createAndWriteFile path $ renderDot $ toDot dot_file where
+        dot_file = graphToDot Params {
+                                             isDirected = True
+                                            ,globalAttributes = []
+                                            ,clusterBy = (\(n,nl) -> case () of
+                                                                  _ | (n `mod` 2) == 0 -> (C 0 $ N (n,nl))
+                                                                    | (n `mod` 2) == 1 -> (C 1 $ N (n,nl)))
+                                            ,isDotCluster = const True
+                                            ,clusterID = Num . Int
+                                            ,fmtCluster = const []
+                                            ,fmtNode = \(n,label)-> [Label (StrLabel (L.pack label)), fmtColorN n]
+                                            ,fmtEdge= \e@(n1,n2,label)-> [Label (StrLabel (L.pack label)), fmtColorE e]
+                                          } (diagToGraph f)
+                    where
+                        fmtColorN n   | n `mod` 4 == 0 = color Green
+                                      | n `mod` 4 == 1 = color Blue
+                                      | n `mod` 4 == 2 = color Red
+                                      | n `mod` 4 == 3 = color Pink
+                        fmtColorE (s,t,_)   | s `mod ` 4 == 0 = if t `mod` 2 == 1 then color Red else color Green
+                                            | t `mod ` 4 == 0 = color Green
+                                            | s `mod ` 4 == 1 = color Blue
+                                            | t `mod ` 4 == 1 = color Blue
+                                            | otherwise = color Black
+            
+    -- | Export a diagram as a pdf with GraphViz such that the source category is in green, the target in blue, each morphism is represented by a node.
+    diagToPdf :: (Morphism m1 o1, FiniteCategory c1 m1 o1, Eq o1, Eq m1, PrettyPrintable m1, PrettyPrintable o1,
+                  Morphism m2 o2, FiniteCategory c2 m2 o2, Eq o2, Eq m2, PrettyPrintable m2, PrettyPrintable o2) =>
+                 (Diagram c1 m1 o1 c2 m2 o2) -> String -> IO ()
+    diagToPdf f path =  dotToPdf (diagToDot f path) path
+    
+    
+    -- __________________________________
+    -- __________________________________
+    --
+    -- Diagram representation as a selection of the target category
+    -- __________________________________
+    -- __________________________________
+    
+    -- | Export a diagram with GraphViz such that a node or an arrow is in orange if it is the target of the functor.
+    diagToDot2 :: (Morphism m1 o1, FiniteCategory c1 m1 o1, Eq o1, Eq m1, PrettyPrintable m1, PrettyPrintable o1,
+                   Morphism m2 o2, FiniteCategory c2 m2 o2, Eq o2, Eq m2, PrettyPrintable m2, PrettyPrintable o2) =>
+                  (Diagram c1 m1 o1 c2 m2 o2) -> String -> IO ()
+    diagToDot2 f@Diagram{src=s,tgt=t,omap=om,mmap=fm} path = createAndWriteFile path $ renderDot $ toDot dot_file where
+        dot_file = graphToDot nonClusteredParams { fmtNode= \(n,label)-> [Label (StrLabel (L.pack label)), colorNode n],
+                                                   fmtEdge= \(n1,n2,label)-> [Label (StrLabel (L.pack label)), colorEdge label]} (categoryToGraph t)
+                                                   where
+                                                        colorNode n = case () of
+                                                                        _ | countPredN == 0 -> color Black
+                                                                          | countPredN == 1 -> color Orange
+                                                                          | countPredN == 2 -> color Orange1
+                                                                          | countPredN == 3 -> color Orange2
+                                                                          | countPredN == 4 -> color Orange3
+                                                                          | countPredN == 5 -> color Orange4
+                                                                          | otherwise -> color OrangeRed4
+                                                                        
+                                                            where
+                                                                countPredN = length [1 | o <- (ob s), (objToNode t (om !-! o)) == n]
+                                                        colorEdge e = case () of
+                                                                        _ | countPredE == 0 -> color Black
+                                                                          | countPredE == 1 -> color Orange
+                                                                          | countPredE == 2 -> color Orange1
+                                                                          | countPredE == 3 -> color Orange2
+                                                                          | countPredE == 4 -> color Orange3
+                                                                          | countPredE == 5 -> color Orange4
+                                                                          | otherwise -> color OrangeRed4
+                                                            where
+                                                                countPredE = length [1 | m <- (arrows s), (pprint (fm !-! m)) == e]
+    
+    -- | Export a diagram as a pdf with GraphViz such that a node or an arrow is in orange if it is the target of the functor.
+    diagToPdf2 :: (Morphism m1 o1, FiniteCategory c1 m1 o1, Eq o1, Eq m1, PrettyPrintable m1, PrettyPrintable o1,
+                  Morphism m2 o2, FiniteCategory c2 m2 o2, Eq o2, Eq m2, PrettyPrintable m2, PrettyPrintable o2) =>
+                 (Diagram c1 m1 o1 c2 m2 o2) -> String -> IO ()
+    diagToPdf2 f path =  dotToPdf (diagToDot2 f path) path
+    
+    -- __________________________________
+    -- __________________________________
+    --
+    -- Natural transformation representation as a translation in the target category.
+    -- __________________________________
+    -- __________________________________
+    
+    -- | Export a natural transformation with GraphViz such that the source diagram is in green, the target diagram is in blue and the translation is in yellow.
+    natToDot ::   (Morphism m1 o1, FiniteCategory c1 m1 o1, Eq o1, Eq m1, PrettyPrintable m1, PrettyPrintable o1,
+                   Morphism m2 o2, FiniteCategory c2 m2 o2, Eq o2, Eq m2, PrettyPrintable m2, PrettyPrintable o2) =>
+                  (NaturalTransformation c1 m1 o1 c2 m2 o2) -> String -> IO ()
+    natToDot NaturalTransformation{srcNT=s,tgtNT=t,component=c} path = createAndWriteFile path $ renderDot $ toDot dot_file where
+        dot_file = graphToDot nonClusteredParams { fmtNode= \(n,label)-> [Label (StrLabel (L.pack label)), colorNode n],
+                                                   fmtEdge= \(n1,n2,label)-> [Label (StrLabel (L.pack label)), colorEdge label]} (categoryToGraph (tgt s))
+                                                   where
+                                                        colorNode n = case () of
+                                                                        _ | predNSrc && predNTgt -> color Turquoise
+                                                                          | predNSrc -> color Green
+                                                                          | predNTgt -> color Blue
+                                                                          | otherwise -> color Black      
+                                                            where
+                                                                predNSrc = foldr (||) False [(objToNode (tgt s) ((omap s) !-! o)) == n | o <- (ob (src s))]
+                                                                predNTgt = foldr (||) False [(objToNode (tgt t) ((omap t) !-! o)) == n | o <- (ob (src t))]
+                                                        colorEdge e = case () of
+                                                                        _ | predESrc && predETgt && predENat -> color Beige
+                                                                          | predESrc && predETgt -> color Turquoise
+                                                                          | predESrc && predENat -> color Orange
+                                                                          | predETgt && predENat -> color LightBlue
+                                                                          | predESrc -> color Green
+                                                                          | predETgt -> color Blue
+                                                                          | predENat -> color Yellow
+                                                                          | otherwise -> color Black
+                                                            where
+                                                                predESrc = foldr (||) False [(pprint ((mmap s) !-! m)) == e | m <- (arrows (src s))]
+                                                                predETgt = foldr (||) False [(pprint ((mmap t) !-! m)) == e | m <- (arrows (src t))]
+                                                                predENat = foldr (||) False [(pprint (c o)) == e | o <- (ob (src s))]
+              
+    -- | Export a natural transformation as pdf with GraphViz such that the source diagram is in green, the target diagram is in blue and the translation is in yellow.
+    natToPdf :: (Morphism m1 o1, FiniteCategory c1 m1 o1, Eq o1, Eq m1, PrettyPrintable m1, PrettyPrintable o1,
+                  Morphism m2 o2, FiniteCategory c2 m2 o2, Eq o2, Eq m2, PrettyPrintable m2, PrettyPrintable o2) =>
+                 (NaturalTransformation c1 m1 o1 c2 m2 o2) -> String -> IO ()
+    natToPdf nt path =  dotToPdf (natToDot nt path) path
+    
+    -- __________________________________
+    -- __________________________________
+    --
+    -- Cone representation as a translation in the reduced target category.
+    -- __________________________________
+    -- __________________________________
+    
+    -- | Export a cone with GraphViz such that the legs are in yellow.
+    extractFromTarget :: (Morphism m1 o1, FiniteCategory c1 m1 o1, Eq o1, Eq m1,
+                          Morphism m2 o2, FiniteCategory c2 m2 o2, Eq o2, Eq m2) =>
+                          (NaturalTransformation c1 m1 o1 c2 m2 o2) -> (FreeSubcategory c2 m2 o2)
+    extractFromTarget NaturalTransformation{srcNT=s,tgtNT=t,component=c} = FreeSubcategory (tgt s) ([(mmap s) !-! m | m <- (arrows (src s))]++[(mmap t) !-! m | m <- (arrows (src s))]++[c o | o <- (ob (src s))])
+    
+    -- | Export a cone with GraphViz such that the source diagram is in green, the target diagram is in blue and the translation is in yellow.
+    coneToDot ::   (Morphism m1 o1, FiniteCategory c1 m1 o1, Eq o1, Eq m1, PrettyPrintable m1, PrettyPrintable o1,
+                   Morphism m2 o2, FiniteCategory c2 m2 o2, Eq o2, Eq m2, PrettyPrintable m2, PrettyPrintable o2) =>
+                  (NaturalTransformation c1 m1 o1 c2 m2 o2) -> String -> IO ()
+    coneToDot nt@NaturalTransformation{srcNT=s,tgtNT=t,component=c} path = createAndWriteFile path $ renderDot $ toDot dot_file where
+        dot_file = graphToDot nonClusteredParams { fmtNode= \(n,label)-> [Label (StrLabel (L.pack label)), colorNode n],
+                                                   fmtEdge= \(n1,n2,label)-> [Label (StrLabel (L.pack label)), colorEdge label]} (categoryToGraph (extractFromTarget nt))
+                                                   where
+                                                        colorNode n = case () of
+                                                                        _ | predNSrc && predNTgt -> color Turquoise
+                                                                          | predNSrc -> color Green
+                                                                          | predNTgt -> color Blue
+                                                                          | otherwise -> color Black      
+                                                            where
+                                                                predNSrc = foldr (||) False [(objToNode (tgt s) ((omap s) !-! o)) == n | o <- (ob (src s))]
+                                                                predNTgt = foldr (||) False [(objToNode (tgt t) ((omap t) !-! o)) == n | o <- (ob (src t))]
+                                                        colorEdge e = case () of
+                                                                        _ | predESrc && predETgt && predENat -> color Beige
+                                                                          | predESrc && predETgt -> color Turquoise
+                                                                          | predESrc && predENat -> color Orange
+                                                                          | predETgt && predENat -> color LightBlue
+                                                                          | predESrc -> color Green
+                                                                          | predETgt -> color Blue
+                                                                          | predENat -> color Yellow
+                                                                          | otherwise -> color Black
+                                                            where
+                                                                predESrc = foldr (||) False [(pprint ((mmap s) !-! m)) == e | m <- (arrows (src s))]
+                                                                predETgt = foldr (||) False [(pprint ((mmap t) !-! m)) == e | m <- (arrows (src t))]
+                                                                predENat = foldr (||) False [(pprint (c o)) == e | o <- (ob (src s))]
+              
+    -- | Export a cone as pdf with GraphViz such that the source diagram is in green, the target diagram is in blue and the translation is in yellow.
+    coneToPdf :: (Morphism m1 o1, FiniteCategory c1 m1 o1, Eq o1, Eq m1, PrettyPrintable m1, PrettyPrintable o1,
+                  Morphism m2 o2, FiniteCategory c2 m2 o2, Eq o2, Eq m2, PrettyPrintable m2, PrettyPrintable o2) =>
+                 (NaturalTransformation c1 m1 o1 c2 m2 o2) -> String -> IO ()
+    coneToPdf nt path =  dotToPdf (coneToDot nt path) path
+ src/FiniteCategory/FiniteCategory.hs view
@@ -0,0 +1,311 @@+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies  #-}
+
+{-| Module  : FiniteCategories
+Description : Typeclasses of morphisms and finite categories and general functions on them.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+The goal of this module is to represent small finite categories in order to make usual constructions automatically on them (e.g. (co)limits, (co)completion, etc.)
+There is a package that deals with categories as a data type (Data.Category) but it does not provide Ar and Ob operators because
+the package uses the fact that the language itself is a category to represent categories
+(Hask is (almost) a category, Data.Category benefit from type check at compilation time).
+The counterpart is that to use Data.Category, you need to create yourself the usual constructions on your category.
+To construct automatically (co)limits and other constructions, we require that the category can enumerate every morphisms between two objects.
+We also require that the objects are not types because we want to create objects at runtime (that is why we abandon type check at
+compilation time for the structure of our categories).
+Lastly, we require that morphisms can be equated for usual constructions purposes.
+
+For example, see the FinSet category and the Composition Graph.
+-}
+
+module FiniteCategory.FiniteCategory
+(
+    -- * Morphism typeclass and related functions
+    Morphism(..),
+    compose,
+    -- * FiniteCategory typeclass
+    FiniteCategory(..),
+    -- * FiniteCategory functions
+    arFrom,
+    arFrom2,
+    arTo,
+    arTo2,
+    identities,
+    isIdentity,
+    isNotIdentity,
+    isTerminal,
+    isInitial,
+    terminalObjects,
+    initialObjects,
+    -- * GeneratedFiniteCategory typeclass and related functions
+    GeneratedFiniteCategory(..),
+    genArFrom,
+    genArFrom2,
+    genArTo,
+    genArTo2,
+    defaultGenAr,
+    defaultDecompose,
+    bruteForceDecompose,
+    isGenerator,
+    isComposite,
+    -- * Check for category correctness
+    FiniteCategoryError(..),
+    checkFiniteCategoryProperties,
+    checkGeneratedFiniteCategoryProperties
+)
+where
+    
+    import Data.List            (elemIndex, elem, concat, nub, intersect, (\\))
+    import Data.Maybe           (fromJust)
+    import Utils.Tuple
+    import IO.PrettyPrint
+    
+    -- | A morphism can be composed with the ('@') operator, it has a source and a target.
+    --
+    -- The ('@') operator should not be confused with the as-pattern. When using the operator, surround the '@' symbol with spaces.
+    --
+    -- Morphism is a multiparametrized type class where /m/ is the type of the morphism and /o/ the type of the objects source and target.
+    -- Source and target are the same type of objects, we distinguish objects not by their type but instead by their values.
+    class Morphism m o | m -> o where
+        -- | The composition @g\@f@ should throw an error if @source g != target f@.
+        -- This is a consequence of loosing type check at compilation time, we defer the exception handling to execution time.
+        --
+        -- Composition is associative :
+        --
+        -- prop> f @ (g @ h) = (f @ g) @ h
+        (@) :: m -> m -> m
+        source :: m -> o
+        target :: m -> o
+        
+    -- | Returns the composition of the list of morphisms.
+    --
+    -- For example :
+    -- @compose [f,g,h] = f \@ g \@ h@
+    compose :: (Morphism m o) => [m] -> m
+    compose l = foldr1 (@) l
+        
+    -- | A category is multiparametrized by the type of its morphisms and the type of its objects. 
+    class FiniteCategory c m o | c -> m, m -> o where
+        -- | `ob` should return a list of unique objects :
+        --
+        -- prop> List.nub (ob c) = ob c
+        ob :: c -> [o]
+        -- | `identity` should return the identity associated to the object /o/ in the category /c/.
+        -- 
+        -- The identity morphism is a morphism such that the two following properties are verified :
+        --
+        -- prop> f @ identity c (source f) = f
+        -- prop> identity c (target g) @ g = g
+        identity :: (Morphism m o) => c -> o -> m
+        -- | `ar` should return the list of all unique arrows between a source and a target :
+        --
+        -- prop> List.nub (ar c s t) = ar c s t
+        --
+        -- Arrows with different source or target should not be equal :
+        --
+        -- prop> (s1 = s2 && t1 = t2) || List.intersect (ar c s1 t1) (ar c s2 t2) = []
+        ar :: (Morphism m o) => c -- ^ The category 
+            -> o -- ^ The source of the morphisms
+            -> o -- ^ The target of the morphisms
+            -> [m] -- ^ The list of morphisms in the category c between source and target
+        
+        {-# MINIMAL ob, identity, ar #-}
+        
+        -- | `arrows` returns the list of all unique morphisms of a category.
+        arrows :: (FiniteCategory c m o, Morphism m o) => c -> [m]
+        arrows c = concat [ar c s t | s <- ob c, t <- ob c]
+       
+        
+    -- | `arTo` returns the list of unique morphisms going to a specified target.
+    arTo :: (FiniteCategory c m o, Morphism m o) => c -> o -> [m]
+    arTo c t = concat [ar c s t | s <- ob c]
+
+    -- | `arTo2` same as `arTo` but for multiple targets.
+    arTo2 :: (FiniteCategory c m o, Morphism m o) => c -> [o] -> [m]
+    arTo2 c ts = concat [ar c s t | s <- ob c, t <- ts]
+
+    -- | `arFrom` returns the list of unique morphisms going from a specified source.
+    arFrom :: (FiniteCategory c m o, Morphism m o) => c -> o -> [m]
+    arFrom c s = concat [ar c s t | t <- ob c]
+
+    -- | `arFrom2` same as `arFrom` but for multiple sources.
+    arFrom2 :: (FiniteCategory c m o, Morphism m o) => c -> [o] -> [m]
+    arFrom2 c ss = concat [ar c s t | t <- ob c, s <- ss]
+
+    -- | `identities` returns all the identities of a category.
+    identities :: (FiniteCategory c m o, Morphism m o) => c -> [m]
+    identities c = identity c <$> ob c
+    
+    -- | Returns wether a morphism is an identity in a category.
+    isIdentity :: (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => c -> m -> Bool
+    isIdentity c m = identity c (source m) == m
+    
+    -- | Returns wether a morphism is not an identity.
+    isNotIdentity :: (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => c -> m -> Bool
+    isNotIdentity c m = not (isIdentity c m)
+
+    -- | Returns wether an object is initial in the category.
+    isInitial :: (FiniteCategory c m o, Morphism m o) => c -> o -> Bool
+    isInitial cat obj = and [(not.null $ ar cat obj t) && (null $ tail (ar cat obj t)) | t <- ob cat]
+    
+    -- | Returns the list of intial objects in a category.
+    initialObjects :: (FiniteCategory c m o, Morphism m o) => c -> [o]
+    initialObjects cat = filter (isInitial cat) (ob cat)
+    
+    -- | Returns wether an object is terminal in the category.
+    isTerminal :: (FiniteCategory c m o, Morphism m o) => c -> o -> Bool
+    isTerminal cat obj = and [(not.null $ ar cat s obj) && (null $ tail (ar cat s obj)) | s <- ob cat] -- we construct this convoluted condition to avoid length which would compute all the arrows between s and obj even when unnecessary (beyond two arrows it's useless) 
+        
+    -- | Returns the list of terminal objects in a category.
+    terminalObjects :: (FiniteCategory c m o, Morphism m o) => c -> [o]
+    terminalObjects cat = filter (isTerminal cat) (ob cat)
+        
+    -- | `GeneratedFiniteCategory` is a `FiniteCategory` where some morphisms are selected as generators.
+    -- The full category is generated by the generating arrows, which means that every morphism can be written as a composition of several generators.
+    -- Some algorithms are simplified because they only need to deal with generators, the rest of the properties are deduced by composition.
+    -- Every `FiniteCategory` has at least one set of generators : the set of all of its morphisms.
+    class (FiniteCategory c m o) => GeneratedFiniteCategory c m o where
+        -- | Same as `ar` but only returns the generators. @genAr c s t@ should be included in @ar c s t@. 
+        genAr :: (Morphism m o) => c -> o -> o -> [m]
+        
+        -- | `decompose` decomposes a morphism into a list of generators (according to composition) :
+        --
+        -- prop> m = compose (decompose c m) 
+        decompose :: (Morphism m o) => c -> m -> [m]
+        
+        {-# MINIMAL genAr, decompose #-}
+        
+        -- | Same as `arrows` but only returns the generators. @genArrows c@ should be included in @arrows c@.  
+        genArrows :: (GeneratedFiniteCategory c m o, Morphism m o) => c -> [m]
+        genArrows c = concat [genAr c s t | s <- ob c, t <- ob c]
+
+    -- | Same as `arTo` but only returns the generators. @genArTo c t@ should be included in @arTo c t@.       
+    genArTo :: (GeneratedFiniteCategory c m o, Morphism m o) => c -> o -> [m]
+    genArTo c t = concat [genAr c s t | s <- ob c] 
+        
+    -- | Same as `arTo2` but only returns the generators. @genArTo2 c [t]@ should be included in @arTo2 c [t]@.  
+    genArTo2 :: (GeneratedFiniteCategory c m o, Morphism m o) => c -> [o] -> [m]
+    genArTo2 c ts = concat [genAr c s t | s <- ob c, t <- ts] 
+        
+    -- | Same as `arFrom` but only returns the generators. @genArFrom c s@ should be included in @arFrom c s@.  
+    genArFrom :: (GeneratedFiniteCategory c m o, Morphism m o) => c -> o -> [m]
+    genArFrom c s = concat [genAr c s t | t <- ob c] 
+        
+    -- | Same as `arFrom2` but only returns the generators. @genArFrom2 c [s]@ should be included in @arFrom2 c [t]@.  
+    genArFrom2 :: (GeneratedFiniteCategory c m o, Morphism m o) => c -> [o] -> [m]
+    genArFrom2 c ss = concat [genAr c s t | t <- ob c, s <- ss] 
+        
+    -- | Every `FiniteCategory` has at least one set of generators : the set of all of its morphisms.
+    --
+    -- `defaultGenAr` is a default method for `genAr` in order to transform any `FiniteCategory` into a `GeneratedFiniteCategory`.
+    --
+    -- Use `defaultGenAr` in conjonction with `defaultDecompose`.
+    defaultGenAr :: (GeneratedFiniteCategory c m o, Morphism m o) => c -> o -> o -> [m]
+    defaultGenAr = ar
+    
+    -- | Every `FiniteCategory` has at least one set of generators : the set of all of its morphisms.
+    --
+    -- `defaultDecompose` is a default method for `decompose` in order to transform any `FiniteCategory` into a `GeneratedFiniteCategory`.
+    --
+    -- Use `defaultDecompose` in conjonction with `defaultGenAr`.
+    defaultDecompose :: (GeneratedFiniteCategory c m o, Morphism m o) => c -> m -> [m]
+    defaultDecompose _ m = (m:[])
+    
+    -- | Helper function for `bruteForceDecompose`.
+    bruteForce :: (GeneratedFiniteCategory c m o, Morphism m o, Eq m) => c -> m -> [[m]] -> [m]
+    bruteForce c m l = if index == Nothing then bruteForce c m (concat (pathToAugmentedPaths <$> l)) else l !! (fromJust index) where
+        index = elemIndex m (compose <$> l)
+        leavingMorph path = (genArFrom c) $ target.head $ path
+        pathToAugmentedPaths path = (leavingMorph path) >>= (\x -> [(x:path)] )   
+    
+    -- | If `genAr` is implemented, we can find the decomposition of a morphism by bruteforce search (we compose every arrow until we get the morphism we want).
+    --
+    -- This method is meant to be used temporarly until a proper decompose method is implemented. (It is very slow.)
+    bruteForceDecompose :: (GeneratedFiniteCategory c m o, Morphism m o, Eq m) => c -> m -> [m]
+    bruteForceDecompose c m = bruteForce c m ((:[]) <$> genArFrom c (source m))  
+    
+    -- | Returns if a morphism is a generating morphism.
+    -- It can be overloaded to speed it up (for a morphism /f/, it computes every generators between the source and the target of /f/ and checks if /f/ is in the list.)
+    isGenerator :: (GeneratedFiniteCategory c m o, Morphism m o, Eq m) => c -> m -> Bool
+    isGenerator c f = elem f (genAr c (source f) (target f))
+    
+    -- | Opposite of `isGenerator`, i.e. returns if the morphism is composite.
+    isComposite :: (GeneratedFiniteCategory c m o, Morphism m o, Eq m) => c -> m -> Bool
+    isComposite c f = not (isGenerator c f)
+
+    -- | A data type to represent an incoherence inside a category.
+    data FiniteCategoryError m o =
+                         CompositionNotAssociative {f :: m, g :: m, h :: m, fg_h :: m, f_gh :: m} -- ^ @(h\@g)\@f /= h\@(g\@f)@
+                       | ObjectsNotUnique {dupObj :: o} -- ^ `dupObj` was found multiple times in @ob c@.
+                       | MorphismsNotUnique {dupMorph :: m} -- ^ `dupMorph` was found multiple times in the category.
+                       | ArrowsNotExhaustive {missingAr :: m} -- ^ `missingAr` is an arrow found by calling @ar c@ but is not in @arrows c@.
+                       | ArrowBetweenUnknownObjects {f :: m, s :: o, t :: o} -- ^ `f` was found in the category but its source `s` or target `t` is not in @ob c@. 
+                       | WrongSource {f :: m, realSource :: o} -- ^ `f` was found by using @ar c s t@ where @s /= source f@.
+                       | WrongTarget {f :: m, realTarget :: o} -- ^ `f` was found by using @ar c s t@ where @t /= target f@.
+                       | IdentityNotLeftNeutral {idL :: m, f :: m, foidL :: m} -- ^ `idL` is not a valid identity : @f \@ idL /= f@.
+                       | IdentityNotRightNeutral {f :: m, idR :: m, idRof :: m} -- ^ `idR` is not a valid identity : @idR \@ f /= f@.
+                       | MorphismsShouldNotBeEqual {f :: m, g :: m} -- ^ @f == g@ even though they don'y share the same source or target.
+                       | NotTransitive {f :: m, g :: m} -- ^ @f\@g@ is not an element of @ar c (source g) (target g)@.
+                       | GeneratorIsNotAMorphism {f :: m} -- ^ `f` is a generator but not a morphism.
+                       | MorphismDoesntDecomposesIntoGenerators {f :: m, decomp :: [m], notGen :: m} -- ^ The morphism `f` decomposes into `decomp` where `notGen` is a non generating morphism.
+                       | WrongDecomposition {f :: m, decomp :: [m], comp :: m} -- ^ @compose (decompose c f) /= f@.
+                       deriving (Eq, Show)
+
+    -- | Checks every properties listed above for a category.
+    --
+    -- If an error is found in the category, just a `FiniteCategoryError` is returned.
+    -- Otherwise, nothing is returned.
+    checkFiniteCategoryProperties :: (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => c -> Maybe (FiniteCategoryError m o)
+    checkFiniteCategoryProperties c
+        | (not.null) dupObjects = Just ObjectsNotUnique {dupObj=head dupObjects}
+        | (not.null) incoherentEq = Just MorphismsShouldNotBeEqual {f=(fst.head) incoherentEq, g=(snd.head) incoherentEq}
+        | (not.null) wrongSource = Just WrongSource {f = (fst.head) wrongSource, realSource = (snd.head) wrongSource}
+        | (not.null) wrongTarget = Just WrongTarget {f = (fst.head) wrongTarget, realTarget = (snd.head) wrongTarget}
+        | (not.null) dupMorph = Just MorphismsNotUnique {dupMorph=head dupMorph}
+        | (not.null) missingAr = Just ArrowsNotExhaustive {missingAr=head missingAr}
+        | (not.null) unknownObjects = Just ArrowBetweenUnknownObjects {f=(fst3.head) unknownObjects, s=(snd3.head) unknownObjects, t=(trd3.head) unknownObjects}
+        | (not.null) idNotLNeutral = Just IdentityNotLeftNeutral {idL=(fst3.head) idNotLNeutral, f=(snd3.head) idNotLNeutral,foidL=(trd3.head) idNotLNeutral} 
+        | (not.null) idNotRNeutral = Just IdentityNotRightNeutral {f=(fst3.head) idNotRNeutral, idR=(snd3.head) idNotRNeutral,idRof=(trd3.head) idNotRNeutral} 
+        | (not.null) notAssociative = Just CompositionNotAssociative {f=(fst3.head) notAssociative,g=(snd3.head) notAssociative,h=(trd3.head) notAssociative, fg_h=(((fst3.head)notAssociative) @ ((snd3.head)notAssociative)) @ ((trd3.head)notAssociative),
+                        f_gh=((fst3.head)notAssociative) @ (((snd3.head)notAssociative) @ ((trd3.head)notAssociative))}
+        | (not.null) notTransitive = Just NotTransitive {f=(fst.head) notTransitive, g=(snd.head) notTransitive}
+        | otherwise = Nothing
+        where
+            dupObjects = ob c \\ nub (ob c)
+            arrowsByAr = concat [ar c s t | s <- (ob c), t <- (ob c)]
+            incoherentEq = [(f,g) | f <- arrows c, g <- arrows c, f == g && (source f /= source g || target f /= target g)]
+            wrongSource = [(f,s) | s <- ob c, t <- ob c, f <- ar c s t, source f /= s]
+            wrongTarget = [(f,t) | s <- ob c, t <- ob c, f <- ar c s t, target f /= t]
+            dupMorph = arrowsByAr \\ nub arrowsByAr
+            missingAr = arrowsByAr \\ (arrows c)
+            unknownObjects = [(f,source f,target f) | f <- arrows c, not ( (source f) `elem` (ob c) && (target f) `elem` (ob c) )]
+            idNotLNeutral = [(identity c (source f),f,f @ identity c (source f)) | f <- arrows c, f @ identity c (source f) /= f]
+            idNotRNeutral = [(f,identity c (target f), identity c (target f) @ f) | f <- arrows c, identity c (target f) @ f /= f]
+            notAssociative = [(x,y,z) | z <- arrows c, y <- arFrom c (target z), x <- arFrom c (target y), (x @ y) @ z /= x @ (y @ z)]
+            notTransitive = [(f,g) | g <- arrows c, f <- arFrom c (target g), not (elem (f @ g) (ar c (source g) (target f)))]
+            fst3 (x,_,_) = x
+            snd3 (_,x,_) = x
+            trd3 (_,_,x) = x
+        
+    -- | Same as `checkFiniteCategoryProperties` but for `GeneratedFiniteCategory`.
+    checkGeneratedFiniteCategoryProperties :: (GeneratedFiniteCategory c m o, Morphism m o, Eq m, Eq o) => c -> Maybe (FiniteCategoryError m o)
+    checkGeneratedFiniteCategoryProperties c
+        | errCat /= Nothing = errCat
+        | (not.null) genNotMorph = Just GeneratorIsNotAMorphism {f=head genNotMorph}
+        | (not.null) decompIntoComposite = Just MorphismDoesntDecomposesIntoGenerators {f=(fst3.head) decompIntoComposite, decomp=(snd3.head) decompIntoComposite, notGen=(trd3.head) decompIntoComposite}
+        | (not.null) wrongDecomp = Just WrongDecomposition {f=(fst3.head) wrongDecomp, decomp=(snd3.head) wrongDecomp, comp=(trd3.head) wrongDecomp}
+        | otherwise = Nothing 
+        where 
+            errCat = checkFiniteCategoryProperties c
+            genNotMorph = genArrows c \\ arrows c
+            decompIntoComposite = [(m,decompose c m,f) | m <- arrows c, f <- decompose c m, not (elem f (genAr c (source f) (target f)))]
+            wrongDecomp = [(f,decompose c f, compose (decompose c f)) | f <- arrows c, compose (decompose c f) /= f]
+            fst3 (x,_,_) = x
+            snd3 (_,x,_) = x
+            trd3 (_,_,x) = x
+            
+    instance (Show m, Show o) => PrettyPrintable (FiniteCategoryError m o) where
+        pprint = show
+ src/FunctorCategory/FunctorCategory.hs view
@@ -0,0 +1,128 @@+{-# LANGUAGE MultiParamTypeClasses  #-}
+
+{-| Module  : FiniteCategories
+Description : Given two categories C and D, the `FunctorCategory` D^C has as objects functors from C to D and as morphisms natural transformations between functors.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Given two categories C and D, the `FunctorCategory` D^C has as objects functors from C to D and as morphisms natural transformations between functors.
+-}
+
+module FunctorCategory.FunctorCategory
+(
+    NaturalTransformation(..),
+    preWhiskering,
+    postWhiskering,
+    FunctorCategory(..)
+)
+where
+    import FiniteCategory.FiniteCategory
+    import Diagram.Diagram
+    import Data.List                               (intercalate)
+    import Utils.EnumerateMaps
+    import Utils.CartesianProduct
+    import Data.Maybe                              (isJust, fromJust)
+    import IO.PrettyPrint
+    import IO.Show
+    import Utils.AssociationList
+    
+    -- | A `NaturalTransformation` between two heterogeneous functors from /C/ to /D/ is a mapping from objects of /C/ to morphism of /D/ such that naturality is respected.
+    --
+    -- Formally, let /F/ and /G/ be functors, and eta : Ob(/C/) -> Ar(/D/). The following property should be respected :
+    --
+    -- prop> source F = source G
+    -- prop> target F = target G
+    -- prop> Forall f in arrows (source F) : eta(target f) @ F(f) = G(f) @ eta(source f)
+    data NaturalTransformation c1 m1 o1 c2 m2 o2 = NaturalTransformation {srcNT :: Diagram c1 m1 o1 c2 m2 o2
+                                                                        , tgtNT :: Diagram c1 m1 o1 c2 m2 o2
+                                                                        , component :: o1 -> m2}
+    
+    instance   (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq c1, Eq m1, Eq o1,
+                FiniteCategory c2 m2 o2, Morphism m2 o2, Eq c2, Eq m2, Eq o2) => 
+                Morphism (NaturalTransformation c1 m1 o1 c2 m2 o2) (Diagram c1 m1 o1 c2 m2 o2) where
+        (@) NaturalTransformation{srcNT=s2,tgtNT=t2,component=c2} NaturalTransformation{srcNT=s1,tgtNT=t1,component=c1}
+            | t1 /= s2 = error "Illegal composition of natural transformations"
+            | otherwise = NaturalTransformation{srcNT=s1,tgtNT=t2,component=(\x -> (c2 x) @ (c1 x))}
+        source = srcNT
+        target = tgtNT
+        
+    instance (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq c1, Eq m1, Eq o1,
+              FiniteCategory c2 m2 o2, Morphism m2 o2, Eq c2, Eq m2, Eq o2) =>
+              Eq (NaturalTransformation c1 m1 o1 c2 m2 o2) where
+        NaturalTransformation{srcNT=s1,tgtNT=t1,component=c1} == NaturalTransformation{srcNT=s2,tgtNT=t2,component=c2}
+            | s1 /= s2 = False
+            | t1 /= t2 = False
+            | otherwise = and [c1 o == c2 o | o <- (ob.src) s1]
+            
+    instance (FiniteCategory c1 m1 o1, Morphism m1 o1, Show c1, Show m1, Show o1, Eq m1, Eq o1,
+              FiniteCategory c2 m2 o2, Morphism m2 o2, Show c2, Show m2, Show o2) =>
+              Show (NaturalTransformation c1 m1 o1 c2 m2 o2) where
+        show NaturalTransformation{srcNT=s,tgtNT=t,component=c} = "NaturalTransformation{srcNT = "++show s++", tgtNT = "++show t++", component = "++showFunction c ((ob.src) s)++"}"
+           
+    instance (FiniteCategory c1 m1 o1, Morphism m1 o1, PrettyPrintable c1, PrettyPrintable m1, PrettyPrintable o1, Eq m1, Eq o1,
+              FiniteCategory c2 m2 o2, Morphism m2 o2, PrettyPrintable c2, PrettyPrintable m2, PrettyPrintable o2) =>
+              PrettyPrintable (NaturalTransformation c1 m1 o1 c2 m2 o2) where
+        pprint NaturalTransformation{srcNT=s,tgtNT=t,component=c} = "Nat : "++pprint s++" -> "++pprint t++"\\n\\n"++pprintFunction c ((ob.src) s)
+        
+    -- | Checks wether the naturality property of a natural transformation is respected.
+    checkNaturality :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1,
+                                                 Morphism m2 o2, Eq m2, Eq o2) => 
+                        NaturalTransformation c1 m1 o1 c2 m2 o2 -> Bool
+    checkNaturality NaturalTransformation{srcNT=s,tgtNT=t,component=c} = and [((mmap t) !-! f) @ (c (source f)) == (c (target f)) @ ((mmap s) !-! f)| f <- (arrows.src) s]
+        
+    -- | Pre-whiskering as defined in Category Theory for the Sciences (2014) by David I. Spivak
+    preWhiskering :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1
+                    , FiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2
+                    , FiniteCategory c3 m3 o3, Morphism m3 o3) =>
+        NaturalTransformation c2 m2 o2 c3 m3 o3 -> Diagram c1 m1 o1 c2 m2 o2 -> NaturalTransformation c1 m1 o1 c3 m3 o3
+    preWhiskering nt d = NaturalTransformation{   srcNT = (srcNT nt) `composeDiag` d 
+                                                , tgtNT = (tgtNT nt) `composeDiag` d
+                                                , component = (component nt).(assocListToFunct (omap d))}
+                                                
+    -- | Pre-whiskering as defined in Category Theory for the Sciences (2014) by David I. Spivak
+    postWhiskering ::   ( FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1
+                        , FiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2
+                        , FiniteCategory c3 m3 o3, Morphism m3 o3) =>
+        Diagram c2 m2 o2 c3 m3 o3 -> NaturalTransformation c1 m1 o1 c2 m2 o2 -> NaturalTransformation c1 m1 o1 c3 m3 o3
+    postWhiskering d nt = NaturalTransformation{  srcNT = d `composeDiag` (srcNT nt) 
+                                                , tgtNT = d `composeDiag` (tgtNT nt)
+                                                , component = (assocListToFunct (mmap d)).(component nt)}
+        
+        
+    -- | `FunctorCategory` D^C.
+    data FunctorCategory c1 m1 o1 c2 m2 o2 = FunctorCategory {sourceCat :: c1 -- ^ /C/
+                                                            , targetCat :: c2} -- ^ /D/
+                                                            deriving (Eq, Show)
+    
+    enumerateFunctors :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1,
+                          FiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2) =>
+                          c1 -> c2 -> [Diagram c1 m1 o1 c2 m2 o2]
+    enumerateFunctors cat1 cat2 = [Diagram{src=cat1,tgt=cat2,mmap=appF, omap=appO} | appO <- appObj, appF <- concat <$> cartesianProduct [twoObjToMaps a b appO| a <- ob cat1, b <- ob cat1], checkFunctoriality Diagram{src=cat1,tgt=cat2,mmap=appF, omap=appO}]
+            where
+                appObj = enumMaps (ob cat1) (ob cat2)
+                twoObjToMaps a b appO = enumMaps (ar cat1 a b) (ar cat2 (appO !-! a) (appO !-! b))
+    
+    instance (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1,
+              FiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2) =>
+              FiniteCategory (FunctorCategory c1 m1 o1 c2 m2 o2) (NaturalTransformation c1 m1 o1 c2 m2 o2) (Diagram c1 m1 o1 c2 m2 o2) where
+        ob FunctorCategory{sourceCat=cat1, targetCat=cat2} = enumerateFunctors cat1 cat2
+        
+        identity c diag = NaturalTransformation{srcNT=diag,tgtNT=diag,component=(identity (tgt diag)).(assocListToFunct (omap diag))}
+        
+        ar c diag1 diag2 = [NaturalTransformation{srcNT=diag1,tgtNT=diag2,component=mapCompo} | mapCompo <- mapComponent, checkNaturality NaturalTransformation{srcNT=diag1,tgtNT=diag2,component=mapCompo}]
+            where
+                mapComponent = transformToFunction <$> cartesianProduct [(\x -> (o,x)) <$> (ar (tgt diag1) ((omap diag1) !-! o) ((omap diag2) !-! o)) | o <- (ob (src diag1))]
+                transformToFunction ((o,f):xs) x = if o == x then f else transformToFunction xs x
+                    
+    instance (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1,
+              FiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2) =>
+              GeneratedFiniteCategory (FunctorCategory c1 m1 o1 c2 m2 o2) (NaturalTransformation c1 m1 o1 c2 m2 o2) (Diagram c1 m1 o1 c2 m2 o2) where
+        genAr = defaultGenAr
+        decompose = defaultDecompose
+        
+    instance (PrettyPrintable c1, PrettyPrintable c2) =>
+              PrettyPrintable (FunctorCategory c1 m1 o1 c2 m2 o2) where
+        pprint FunctorCategory{sourceCat=s, targetCat=t} = "Fonct("++pprint s++","++pprint t++")"
+ src/IO/CreateAndWriteFile.hs view
@@ -0,0 +1,28 @@+{-| Module  : FiniteCategories
+Description : Write into a file, create directories if necessary.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Write lazy text to a file specified by a path, if the path leads to non existing directories, it creates the directories.
+Credits to wisn : https://stackoverflow.com/a/58685979
+-}
+
+module IO.CreateAndWriteFile
+(
+    createAndWriteFile
+)
+where
+    import System.Directory (createDirectoryIfMissing)
+    import System.FilePath.Posix (takeDirectory)
+    import qualified    Data.Text.Lazy as L                 (Text)
+    import qualified    Data.Text.Lazy.IO as LIO             (writeFile)
+
+    -- | Write lazy text to a file specified by a path, if the path leads to non existing directories, it creates the directories.
+    createAndWriteFile :: FilePath -> L.Text -> IO ()
+    createAndWriteFile path content = do
+        createDirectoryIfMissing True $ takeDirectory path
+
+        LIO.writeFile path content
+ src/IO/Parsers/CompositionGraph.hs view
@@ -0,0 +1,116 @@+{-| Module  : FiniteCategories
+Description : A parser to read .cg files.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+A parser to read .cg files.
+
+A .cg file follows the following rules :
+    1. Each line defines either an object, a morphism or a composition law entry.
+    2. The following strings are reserved : ' -','-> ',' = '
+    3. To define an object, write a line containing its name.
+    4. To define an arrow, the syntax "source_object -name_of_morphism-> target_object" is used, where "source_object", "target_object" and "name_of_morphism" should be replaced.
+    4.1. If an object mentionned does not exist, it is created.
+    4.2. The spaces are important. 
+    5. To define a composition law entry, the syntax "source_object1 -name_of_first_morphism-> middle_object -name_of_second_morphism-> target_object1 = source_object2 -name_of_composite_morphism-> target_object2" is used, where "source_object1", "name_of_first_morphism", "middle_object", "name_of_second_morphism", "target_object1", "source_object2", "name_of_composite_morphism", "target_object2" should be replaced.
+    5.1 If an object mentionned does not exist, it is created.
+    5.2 If a morphism mentionned does not exist, it is created.
+    5.3 You can use the tag <ID/> in order to map a morphism to an identity.
+-}
+
+module IO.Parsers.CompositionGraph
+(
+    readCGFile,
+    writeCGFile
+)
+where
+    import FiniteCategory.FiniteCategory
+    import CompositionGraph.CompositionGraph
+    import IO.Parsers.Lexer
+    import Data.IORef
+    import Data.Text (Text, pack, unpack)
+    import Data.List (elemIndex, nub, intercalate)
+    import Utils.Tuple
+    import IO.PrettyPrint
+    
+    import System.Directory (createDirectoryIfMissing)
+    import System.FilePath.Posix (takeDirectory)
+    
+    type CG = CompositionGraph Text Text
+    
+    addObject :: [Token] -> CG -> CG
+    addObject [Name str] cg@CompositionGraph{graph=(n,a),law=l} = if elem str (ob cg) then cg else CompositionGraph{graph=((str:(ob cg)),a),law=l}
+    addObject otherTokens _ = error $ "addObject on invalid tokens : "++show otherTokens
+    
+    addMorphism :: [Token] -> CG -> CG
+    addMorphism [Name src, BeginArrow, Name arr, EndArrow, Name tgt] cg = if elem (Just arr) (getLabel <$> (ar newCG2 src tgt)) then newCG2 else CompositionGraph{graph=(n,((src,tgt,arr):a)),law=l}
+        where
+            newCG1 = addObject [Name src] cg
+            newCG2@CompositionGraph{graph=(n,a),law=l} = addObject [Name tgt] newCG1
+    addMorphism otherTokens _ = error $ "addMorphism on invalid tokens : "++show otherTokens
+    
+    extractPath :: [Token] -> RawPath Text Text
+    extractPath [] = []
+    extractPath [Identity] = []
+    extractPath [(Name _)] = []
+    extractPath ((Name src) : (BeginArrow : ((Name arr) : (EndArrow : ((Name tgt) : ts))))) = (extractPath ((Name tgt) : ts)) ++ [(src,tgt,arr)]
+    extractPath otherTokens = error $ "extractPath on invalid tokens : "++show otherTokens
+    
+    addCompositionLawEntry :: [Token] -> CG -> CG
+    addCompositionLawEntry tokens cg@CompositionGraph{graph=(n,a),law=l} = CompositionGraph{graph=(n++newObj,a++newMorph),law=(pathLeft,pathRight):l}
+        where
+            Just indexEquals = elemIndex Equals tokens
+            (tokensLeft,(_:tokensRight)) = splitAt indexEquals tokens
+            pathLeft = extractPath tokensLeft
+            pathRight = extractPath tokensRight
+            newObj = nub $ [s | (s,_,_) <- pathLeft++pathRight, not (elem s n)]++[t | (_,t,_) <- pathLeft++pathRight, not (elem t n)]
+            newMorph = nub [e | e <- pathLeft++pathRight, not (elem e a)]
+    
+    readLine :: String -> CG -> CG
+    readLine line cg
+        | null lexedLine = cg
+        | elem Equals lexedLine = addCompositionLawEntry lexedLine cg
+        | elem BeginArrow lexedLine = addMorphism lexedLine cg
+        | otherwise = addObject lexedLine cg
+        where
+            lexedLine = (parserLex line)
+    
+    parseCGString :: String -> CG
+    parseCGString str = newCG
+        where
+            ls = lines str
+            cg = mkEmptyCompositionGraph
+            newCG = foldr readLine cg ls
+    
+    -- | Reads a cg file and returns a composition graph.
+    readCGFile :: String -> IO CG
+    readCGFile path = do
+        file <- readFile path
+        return $ parseCGString file
+        
+    reversedRawPathToString :: (PrettyPrintable a, PrettyPrintable b) => RawPath a b -> String
+    reversedRawPathToString [] = "<ID>"
+    reversedRawPathToString [(s,t,l)] = pprint s ++ " -" ++ pprint l ++ "-> " ++ pprint t
+    reversedRawPathToString ((s,t,l):xs) = pprint s ++ " -" ++ pprint l ++ "-> " ++ reversedRawPathToString xs
+    
+    unparseCG :: (PrettyPrintable a, PrettyPrintable b, Eq a, Eq b) => CompositionGraph a b -> String
+    unparseCG cg = finalString
+        where
+            obString = intercalate "\n" $ pprint <$> ob cg
+            arNotIdentity = filter (isNotIdentity cg) (genArrows cg)
+            reversedRawPaths = (reverse.snd3.path) <$> arNotIdentity
+            arStringBeforeComment = reversedRawPathToString <$> reversedRawPaths
+            commentOutComposite = [if isComposite cg m then ('#':s) else s | (s,m) <- zip arStringBeforeComment arNotIdentity]
+            arString = intercalate "\n" $ commentOutComposite
+            lawString = intercalate "\n" $ (\(rp1,rp2) -> (reversedRawPathToString (reverse rp1)) ++ " = " ++ (reversedRawPathToString (reverse rp2))) <$> (law cg)
+            finalString = "#Objects :\n"++obString++"\n\n# Arrows :\n"++arString++"\n\n# Composition law :\n"++lawString
+    
+    -- | Saves a composition graph into a file located at a given path.
+    writeCGFile :: (PrettyPrintable a, PrettyPrintable b, Eq a, Eq b) => CompositionGraph a b -> String -> IO ()
+    writeCGFile cg filepath = do
+        createDirectoryIfMissing True $ takeDirectory filepath
+        writeFile filepath $ unparseCG cg
+        
+ src/IO/Parsers/Lexer.hs view
@@ -0,0 +1,45 @@+{-| Module  : FiniteCategories
+Description : Lexer for parsers.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Lexer for parsers. The keywords are ' -', '-> ', ' = ', "#", '<ID/>', '<SRC>', '</SRC>', '<TGT>', '</TGT>', ' => '
+-}
+module IO.Parsers.Lexer where
+    import Data.Text (Text, cons, singleton, unpack, pack)
+    
+    -- | A token for a scg or fscg file.
+    data Token = Name Text | BeginArrow | EndArrow | Equals | Identity | BeginSrc | EndSrc | BeginTgt | EndTgt | MapsTo deriving (Eq, Show)
+    
+    -- | Strip a token of unnecessary spaces.
+    strip :: Token -> Token
+    strip (Name txt) = Name (pack.reverse.stripLeft.reverse.stripLeft $ str)
+        where
+            str = unpack txt
+            stripLeft (' ':s) = s 
+            stripLeft s = s 
+    strip x = x
+        
+    -- | Transforms a string into a list of tokens.
+    parserLex :: String -> [Token]
+    parserLex str = strip <$> parserLexHelper str
+        where
+            parserLexHelper [] = [] 
+            parserLexHelper ('#':str) = []
+            parserLexHelper (' ':'-':str) = BeginArrow : (parserLexHelper str)
+            parserLexHelper ('-':'>':' ':str) = EndArrow : (parserLexHelper str)
+            parserLexHelper (' ':'=':' ':str) = Equals : (parserLexHelper str)
+            parserLexHelper ('<':'I':'D':'/':'>':str) = Identity : (parserLexHelper str)
+            parserLexHelper ('<':'S':'R':'C':'>':str) = BeginSrc : (parserLexHelper str)
+            parserLexHelper ('<':'T':'G':'T':'>':str) = BeginTgt : (parserLexHelper str)
+            parserLexHelper ('<':'/':'S':'R':'C':'>':str) = EndSrc : (parserLexHelper str)
+            parserLexHelper ('<':'/':'T':'G':'T':'>':str) = EndTgt : (parserLexHelper str)
+            parserLexHelper (' ':'=':'>':' ':str) = MapsTo : (parserLexHelper str)
+            parserLexHelper (c:str) =  (result restLexed)
+                where
+                    restLexed = (parserLexHelper str)
+                    result (Name txt:xs) = (Name (cons c txt):xs)
+                    result a = ((Name (singleton c)):a)
+ src/IO/Parsers/SafeCompositionGraph.hs view
@@ -0,0 +1,114 @@+{-| Module  : FiniteCategories
+Description : A parser to read .scg files.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+A parser to read .scg files.
+
+A .scg file follows the following rules :
+    1. The first line is an integer specifying the max number of loops morphisms can do.
+    2. The rest of the file is a cg file. (See IO.Parsers.CompositionGraph)
+-}
+
+module IO.Parsers.SafeCompositionGraph 
+(
+    SCG(..),
+    parseSCGString,
+    readSCGFile,
+    writeSCGFile
+)
+where
+    import FiniteCategory.FiniteCategory
+    import CompositionGraph.CompositionGraph
+    import CompositionGraph.SafeCompositionGraph
+    import IO.Parsers.Lexer
+    import Data.IORef
+    import Data.Text (Text, pack, unpack)
+    import Data.List (elemIndex, nub, intercalate)
+    import Utils.Tuple
+    import IO.PrettyPrint
+        
+    import System.Directory (createDirectoryIfMissing)
+    import System.FilePath.Posix (takeDirectory)
+    
+    -- | The type of SafeCompositionGraph created by reading a scg file.
+    type SCG = SafeCompositionGraph Text Text
+    
+    addObject :: [Token] -> SCG -> SCG
+    addObject [Name str] cg@SafeCompositionGraph{graphS=(n,a),lawS=l,maxCycles=mc} = if elem str (ob cg) then cg else SafeCompositionGraph{graphS=((str:(ob cg)),a),lawS=l,maxCycles=mc}
+    addObject otherTokens _ = error $ "addObject on invalid tokens : "++show otherTokens
+    
+    addMorphism :: [Token] -> SCG -> SCG
+    addMorphism [Name src, BeginArrow, Name arr, EndArrow, Name tgt] cg = if elem (Just arr) (getLabelS <$> (ar newSCG2 src tgt)) then newSCG2 else SafeCompositionGraph{graphS=(n,((src,tgt,arr):a)),lawS=l,maxCycles=mc}
+        where
+            newSCG1 = addObject [Name src] cg
+            newSCG2@SafeCompositionGraph{graphS=(n,a),lawS=l,maxCycles=mc} = addObject [Name tgt] newSCG1
+    addMorphism otherTokens _ = error $ "addMorphism on invalid tokens : "++show otherTokens
+    
+    extractPath :: [Token] -> RawPath Text Text
+    extractPath [] = []
+    extractPath [Identity] = []
+    extractPath [(Name _)] = []
+    extractPath ((Name src) : (BeginArrow : ((Name arr) : (EndArrow : ((Name tgt) : ts))))) = (extractPath ((Name tgt) : ts)) ++ [(src,tgt,arr)]
+    extractPath otherTokens = error $ "extractPath on invalid tokens : "++show otherTokens
+    
+    addCompositionLawEntry :: [Token] -> SCG -> SCG
+    addCompositionLawEntry tokens cg@SafeCompositionGraph{graphS=(n,a),lawS=l,maxCycles=mc} = SafeCompositionGraph{graphS=(n++newObj,a++newMorph),lawS=(pathLeft,pathRight):l,maxCycles=mc}
+        where
+            Just indexEquals = elemIndex Equals tokens
+            (tokensLeft,(_:tokensRight)) = splitAt indexEquals tokens
+            pathLeft = extractPath tokensLeft
+            pathRight = extractPath tokensRight
+            newObj = nub $ [s | (s,_,_) <- pathLeft++pathRight, not (elem s n)]++[t | (_,t,_) <- pathLeft++pathRight, not (elem t n)]
+            newMorph = nub [e | e <- pathLeft++pathRight, not (elem e a)]
+    
+    readLine :: String -> SCG -> SCG
+    readLine line cg
+        | null lexedLine = cg
+        | elem Equals lexedLine = addCompositionLawEntry lexedLine cg
+        | elem BeginArrow lexedLine = addMorphism lexedLine cg
+        | otherwise = addObject lexedLine cg
+        where
+            lexedLine = (parserLex line)
+    
+    -- | Parse a string extracted from a scg file. Returns a safe composition graph.
+    parseSCGString :: String -> SCG
+    parseSCGString str = if test then newSCG else error $ "First line of scg file is not a number : "++show ls
+        where
+            test = null $ filter (\x -> not $ elem x ['0'..'9']) $ head ls
+            ls = filter (not.null.parserLex) $ lines str
+            maxCyc = (read $ head ls) :: Int
+            cg = mkEmptySafeCompositionGraph maxCyc
+            newSCG = foldr readLine cg (tail ls)
+        
+    -- | Reads a scg file and returns a safe composition graph.
+    readSCGFile :: String -> IO SCG
+    readSCGFile path = do
+        file <- readFile path
+        return $ parseSCGString file
+        
+    reversedRawPathToString :: (PrettyPrintable a, PrettyPrintable b) => RawPath a b -> String
+    reversedRawPathToString [] = "<ID>"
+    reversedRawPathToString [(s,t,l)] = pprint s ++ " -" ++ pprint l ++ "-> " ++ pprint t
+    reversedRawPathToString ((s,t,l):xs) = pprint s ++ " -" ++ pprint l ++ "-> " ++ reversedRawPathToString xs    
+    
+    unparseSCG :: (PrettyPrintable a, PrettyPrintable b, Eq a, Eq b) => SafeCompositionGraph a b -> String
+    unparseSCG cg = finalString
+        where
+            obString = intercalate "\n" $ pprint <$> ob cg
+            arNotIdentity = filter (isNotIdentity cg) (arrows cg)
+            reversedRawPaths = (reverse.snd3.pathS) <$> arNotIdentity
+            arStringBeforeComment = reversedRawPathToString <$> reversedRawPaths
+            commentOutComposite = [if isComposite cg m then ('#':s) else s | (s,m) <- zip arStringBeforeComment arNotIdentity]
+            arString = intercalate "\n" $ commentOutComposite
+            lawString = intercalate "\n" $ (\(rp1,rp2) -> (reversedRawPathToString (reverse rp1)) ++ " = " ++ (reversedRawPathToString (reverse rp2))) <$> (lawS cg)
+            finalString = "#Max number of cycles :\n"++show (maxCycles cg)++"\n\n#Objects :\n"++obString++"\n\n# Arrows :\n"++arString++"\n\n# Composition law :\n"++lawString
+    
+    -- | Saves a safe composition graph into a file located at a given path.
+    writeSCGFile :: (PrettyPrintable a, PrettyPrintable b, Eq a, Eq b) => SafeCompositionGraph a b -> String -> IO ()
+    writeSCGFile cg filepath = do
+        createDirectoryIfMissing True $ takeDirectory filepath
+        writeFile filepath $ unparseSCG cg
+ src/IO/Parsers/SafeCompositionGraphFunctor.hs view
@@ -0,0 +1,123 @@+{-| Module  : FiniteCategories
+Description : A parser to read .fscg files.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+A parser to read .fscg files.
+
+A .fscg file follows the following rules :
+    1. There is a line "<SRC>" and a line "</SRC>".
+    1.1 Between these two lines, the source safe composition graph is defined as in a scg file.
+    2. There is a line "<TGT>" and a line "</TGT>".
+    2.1 Between these two lines, the target safe composition graph is defined as in a scg file.
+    3. Outside of the two previously described sections, you can declare the maps between objects and morphisms.
+    3.1 You map an object to another with the following syntax : "object1 => object2".
+    3.2 You map a morphism to another with the following syntax : "objSrc1 -arrowSrc1-> objSrc2 => objTgt1 -arrowTgt1-> objTgt2".
+    4. You don't have to (and you shouldn't) specify maps from identities, nor maps from composite arrows.
+-}
+
+module IO.Parsers.SafeCompositionGraphFunctor
+(
+    readFSCGFile
+)
+where
+    import FiniteCategory.FiniteCategory
+    import Cat.PartialFinCat
+    import CompositionGraph.CompositionGraph
+    import CompositionGraph.SafeCompositionGraph
+    import IO.Parsers.Lexer
+    import IO.Parsers.SafeCompositionGraph
+    import Data.IORef
+    import Data.Text (Text, pack, unpack)
+    import Data.List (elemIndex, nub, intercalate)
+    import Utils.Tuple
+    import IO.PrettyPrint
+    import Utils.AssociationList
+    import Diagram.Diagram
+        
+    import System.Directory (createDirectoryIfMissing)
+    import System.FilePath.Posix (takeDirectory)
+    
+    type SCGF = PartialFunctor SCG (SCGMorphism Text Text) Text
+    type SCGD = Diagram SCG (SCGMorphism Text Text) Text SCG (SCGMorphism Text Text) Text
+    
+    addOMapEntry :: [Token] -> SCGF -> SCGF
+    addOMapEntry [Name x, MapsTo, Name y] pf
+        | elem x (keys (omapPF pf)) = if y == ((omapPF pf) !-! x) then pf else error ("Incoherent maps of object : F("++show x++") = "++show y ++ " and "++show ((omapPF pf) !-! x))
+        | otherwise = PartialFunctor{srcPF=srcPF pf, tgtPF=tgtPF pf, omapPF=((x,y):(omapPF pf)), mmapPF=mmapPF pf}
+    addOMapEntry otherTokens _ = error $ "addOMapEntry on invalid tokens : "++show otherTokens
+    
+    addMMapEntry :: [Token] -> SCGF -> SCGF
+    addMMapEntry tks@[Name sx, BeginArrow, Name lx, EndArrow, Name tx, MapsTo, Identity] pf = if elem sx (keys (omapPF pf)) then PartialFunctor{srcPF=srcPF pf, tgtPF=tgtPF pf, omapPF=omapPF pf, mmapPF=((sourceMorph,(identity (target pf) ((omapPF pf) !-! sx))):(mmapPF pf))} else error ("You must specify the image of the source of the morphism before mapping to an identity : "++show tks)
+        where
+            sourceMorphCand = filter (\e -> getLabelS e == Just lx) (genAr (source pf) sx tx)
+            sourceMorph = if null sourceMorphCand then error $ "addMMapEntry : morphism not found in source category for the following map : "++ show tks else head sourceMorphCand
+    addMMapEntry tks@[Name sx, BeginArrow, Name lx, EndArrow, Name tx, MapsTo, Name sy, BeginArrow, Name ly, EndArrow, Name ty] pf = PartialFunctor{srcPF=srcPF newPF2, tgtPF=tgtPF newPF2, omapPF=omapPF newPF2, mmapPF=((sourceMorph,targetMorph):(mmapPF newPF2))}
+        where
+            sourceMorphCand = filter (\e -> getLabelS e == Just lx) (genAr (source pf) sx tx)
+            targetMorphCand = filter (\e -> getLabelS e == Just ly) (genAr (target pf) sy ty)
+            sourceMorph = if null sourceMorphCand then error $ "addMMapEntry : morphism not found in source category for the following map : "++ show tks else head sourceMorphCand
+            targetMorph = if null targetMorphCand then error $ "addMMapEntry : morphism not found in target category for the following map : "++ show tks else head targetMorphCand
+            newPF1 = addOMapEntry [Name sx, MapsTo, Name sy] pf
+            newPF2 = addOMapEntry [Name tx, MapsTo, Name ty] newPF1
+            
+    addMMapEntry otherTokens _ = error $ "addMMapEntry on invalid tokens : "++show otherTokens
+    
+    readLineF :: String -> SCGF -> SCGF
+    readLineF line pf@PartialFunctor{srcPF=s, tgtPF=t, omapPF=om, mmapPF=mm}
+        | null lexedLine = pf
+        | elem MapsTo lexedLine = if elem BeginArrow lexedLine
+            then addMMapEntry lexedLine pf
+            else addOMapEntry lexedLine pf
+        | otherwise = pf
+        where
+            lexedLine = (parserLex line)
+
+    extractSrcSection :: [String] -> [String]
+    extractSrcSection lines
+        | not (elem [BeginSrc] (parserLex <$> lines)) = error $ "No <SRC> section or malformed <SRC> section in file : "++ show lines
+        | not (elem [EndSrc] (parserLex <$> lines)) = error $ "No <SRC> section or malformed <SRC> section in file : "++ show lines
+        | indexEndSrc < indexBeginSrc = error $ "Malformed <SRC> section in file : "++ show lines
+        | otherwise = c
+        where
+            Just indexBeginSrc = (elemIndex [BeginSrc] (parserLex <$> lines))
+            Just indexEndSrc = (elemIndex [EndSrc] (parserLex <$> lines))
+            (a,b) = splitAt (indexBeginSrc+1) lines
+            (c,d) = splitAt (indexEndSrc-indexBeginSrc-1) b
+            
+    extractTgtSection :: [String] -> [String]
+    extractTgtSection lines
+        | not (elem [BeginTgt] (parserLex <$> lines)) = error $ "No <TGT> section or malformed <TGT> section in file : "++ show lines
+        | not (elem [EndTgt] (parserLex <$> lines)) = error $ "No <TGT> section or malformed <TGT> section in file : "++ show lines
+        | indexEndTgt < indexBeginTgt = error $ "Malformed <TGT> section in file : "++ show lines
+        | otherwise = c
+        where
+            Just indexBeginTgt = (elemIndex [BeginTgt] (parserLex <$> lines))
+            Just indexEndTgt = (elemIndex [EndTgt] (parserLex <$> lines))
+            (a,b) = splitAt (indexBeginTgt+1) lines
+            (c,d) = splitAt (indexEndTgt-indexBeginTgt-1) b
+    
+    rawreadFSCGFile :: String -> IO SCGF
+    rawreadFSCGFile path = do
+        file <- readFile path
+        let ls = filter (not.null.parserLex) $ lines file
+        let src = parseSCGString $ intercalate "\n" (extractSrcSection ls)
+        let tgt = parseSCGString $ intercalate "\n" (extractTgtSection ls)
+        let pf = PartialFunctor{srcPF=src, tgtPF=tgt,omapPF=[], mmapPF=[]}
+        let finalPF = foldr readLineF pf ls
+        return finalPF
+    
+    -- | Reads a fscg file and completes everything so that it becomes a diagram.
+    completeFSCG :: SCGF -> SCGD
+    completeFSCG pf@PartialFunctor{srcPF=s, tgtPF=t, omapPF=om, mmapPF=mm} =
+        Diagram{src=s, tgt=t, omap=om, mmap=completeMmap s t om mm}
+        
+    -- | Reads a fscg file and returns a diagram.
+    readFSCGFile :: String -> IO SCGD
+    readFSCGFile path = do
+        raw <- rawreadFSCGFile path
+        return (completeFSCG raw)
+        
+ src/IO/PrettyPrint.hs view
@@ -0,0 +1,67 @@+{-| Module  : FiniteCategories
+Description : A simple typeclass for things to be pretty printed.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+A simple typeclass for things to be pretty printed. Things should be pretty printable to be exported with graphviz.
+-}
+module IO.PrettyPrint
+(
+    PrettyPrintable(..),
+    pprintFunction
+)
+where
+    import Data.List  (intercalate)
+    import Data.Set   (Set, toList)
+    import Data.Map   (Map, keys, (!))
+    import Data.Maybe
+    import Data.Either
+    import Data.Text  (Text, unpack)
+    
+    -- | The typeclass of things that can be pretty printed.
+    class PrettyPrintable a where
+        pprint :: a -> String
+        
+    instance (PrettyPrintable a) => PrettyPrintable [a] where
+        pprint xs = "[" ++ intercalate "," (pprint <$> xs) ++ "]"
+        
+    
+    instance (PrettyPrintable a, PrettyPrintable b) => PrettyPrintable (a,b) where
+        pprint (a,b) = "(" ++ pprint a ++ "," ++ pprint b ++ ")"
+    
+    instance (PrettyPrintable a, PrettyPrintable b, PrettyPrintable c) => PrettyPrintable (a,b,c) where
+        pprint (a,b,c) = "(" ++ pprint a ++ "," ++ pprint b ++ "," ++ pprint c ++ ")"
+        
+    instance (PrettyPrintable a) => PrettyPrintable (Set a) where
+        pprint xs = "{" ++ intercalate "," (pprint <$> (toList xs)) ++ "}"
+        
+    instance PrettyPrintable Int where
+        pprint = show
+        
+    instance PrettyPrintable Double where
+        pprint = show
+        
+    instance PrettyPrintable Char where
+        pprint = show
+        
+    instance (Ord k, PrettyPrintable k, PrettyPrintable a) => PrettyPrintable (Map k a) where
+        pprint m = intercalate "\n" [pprint k ++ "->" ++pprint (m!k)| k <- keys m]
+        
+    instance (PrettyPrintable a) => PrettyPrintable (Maybe a) where
+        pprint Nothing = "Nothing"
+        pprint (Just a) = pprint a
+        
+    instance (PrettyPrintable a, PrettyPrintable b) => PrettyPrintable (Either a b) where
+        pprint (Left x) = pprint x
+        pprint (Right x) = pprint x
+        
+    instance PrettyPrintable Text where
+        pprint = unpack
+    
+    -- | Pretty print a function on a specific domain.
+    pprintFunction :: (PrettyPrintable a, PrettyPrintable b) =>
+                   (a -> b) -> [a] -> String
+    pprintFunction f xs = intercalate "\n" [pprint x ++" -> " ++ pprint (f x) | x <- xs]
+ src/IO/Show.hs view
@@ -0,0 +1,22 @@+{-| Module  : FiniteCategories
+Description : Helpers for instanciating Show.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Helpers for instanciating Show.
+-}
+module IO.Show
+(
+    showFunction
+)
+where
+    import Data.List (intercalate)
+    
+    -- | Show a function on a certain domain.
+    showFunction :: (Show a, Show b) =>
+                   (a -> b) -> [a] -> String
+    showFunction f xs = "(\\x -> case x of " ++ intercalate ";" [show x ++" -> " ++ show (f x) | x <- xs] ++ ")"
+    
+ src/Limit/Limit.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE MultiParamTypeClasses  #-}
+
+{-| Module  : FiniteCategories
+Description : The lim functor which takes every diagram to its limit object. See also ConeCategory for the limit of a specific diagram.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+The lim functor which takes every diagram to its limit object according to the global definition of limit. See also ConeCategory for the limit of a specific diagram.
+-}
+
+module Limit.Limit 
+(
+    limitFunctor,
+    colimitFunctor,
+)
+where
+    import              FiniteCategory.FiniteCategory
+    import              Diagram.Diagram
+    import              Adjunction.Adjunction
+    import              FunctorCategory.FunctorCategory
+    import              DiagonalFunctor.DiagonalFunctor
+    import  IO.PrettyPrint
+    
+    -- | Returns the limit functor according to the global definition of limit (see https://ncatlab.org/nlab/show/limit#global_definition_in_terms_of_adjoint_of_the_constant_diagram_functor).
+    --
+    -- Given an indexing category @J@ and a category @C@, returns a functor which maps each diagram of form @J@ in @C@ to its limit object in @C@. 
+    limitFunctor :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq c1, Eq m1, Eq o1, PrettyPrintable c1, PrettyPrintable c2, PrettyPrintable o1, PrettyPrintable o2, PrettyPrintable m1, PrettyPrintable m2,
+                     FiniteCategory c2 m2 o2, Morphism m2 o2, Eq c2, Eq m2, Eq o2) =>
+                     c1 -> c2 -> Diagram (FunctorCategory c1 m1 o1 c2 m2 o2) (NaturalTransformation c1 m1 o1 c2 m2 o2) (Diagram c1 m1 o1 c2 m2 o2) c2 m2 o2 
+    limitFunctor j c = rightAdjoint $ mkDiagonalFunctor j c
+    
+    -- | Returns the colimit functor according to the global definition of colimit (see https://ncatlab.org/nlab/show/limit#global_definition_in_terms_of_adjoint_of_the_constant_diagram_functor).
+    --
+    -- Given an indexing category @J@ and a category @C@, returns a functor which maps each diagram of form @J@ in @C@ to its colimit object in @C@. 
+    colimitFunctor :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq c1, Eq m1, Eq o1,
+                     FiniteCategory c2 m2 o2, Morphism m2 o2, Eq c2, Eq m2, Eq o2) =>
+                     c1 -> c2 -> Diagram (FunctorCategory c1 m1 o1 c2 m2 o2) (NaturalTransformation c1 m1 o1 c2 m2 o2) (Diagram c1 m1 o1 c2 m2 o2) c2 m2 o2 
+    colimitFunctor j c = leftAdjoint $ mkDiagonalFunctor j c
+ src/OppositeCategory/OppositeCategory.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
+
+{-| Module  : FiniteCategories
+Description : The opposite of a category.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+The opposite of a category is a category with reversed arrows.
+-}
+
+module OppositeCategory.OppositeCategory
+(
+    OppositeMorphism(..),
+    OppositeCategory(..),
+    opOpMorph,
+    opOp
+)
+where
+    import FiniteCategory.FiniteCategory
+    import IO.PrettyPrint
+    
+    -- | Morphism in an opposite category.
+    data OppositeMorphism m o = OpMorph m deriving (Eq, Show, Ord)
+    
+    -- | Transforms back an opposite morphism into the original morphism.
+    opOpMorph :: OppositeMorphism m o -> m
+    opOpMorph (OpMorph m) = m
+    
+    instance (Morphism m o) => Morphism (OppositeMorphism m o) o where
+        source (OpMorph m) = target m
+        target (OpMorph m) = source m
+        (@) (OpMorph g) (OpMorph f) = OpMorph $ f @ g
+        
+    instance (PrettyPrintable m) => PrettyPrintable (OppositeMorphism m o) where
+        pprint (OpMorph m) = "Op "++(pprint m)
+        
+    -- | Opposite category of a given category.
+    data OppositeCategory c m o = Op c deriving (Eq, Show, Ord)
+    
+    -- | Transforms an opposite category into the original category.
+    opOp :: OppositeCategory c m o -> c
+    opOp (Op c) = c
+    
+    instance (FiniteCategory c m o, Morphism m o) => FiniteCategory (OppositeCategory c m o) (OppositeMorphism m o) o where
+        ob (Op c) = ob c
+        identity (Op c) o = OpMorph $ identity c o
+        ar (Op c) s t = OpMorph <$> ar c t s
+    
+    instance (GeneratedFiniteCategory c m o, Morphism m o) => GeneratedFiniteCategory (OppositeCategory c m o) (OppositeMorphism m o) o where
+        genAr (Op c) s t = OpMorph <$> genAr c t s
+        decompose (Op c) (OpMorph m) = OpMorph <$> decompose c m
+        
+    instance (PrettyPrintable c) => PrettyPrintable (OppositeCategory c m o) where
+        pprint (Op cat) = "Op "++(pprint cat)
+ src/ProductCategory/ProductCategory.hs view
@@ -0,0 +1,91 @@+{-# LANGUAGE MultiParamTypeClasses  #-}
+
+{-| Module  : FiniteCategories
+Description : Product category of two categories.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Product category of two categories.
+-}
+module ProductCategory.ProductCategory
+(
+firstObject,
+firstMorphism,
+firstCategory,
+secondObject,
+secondMorphism,
+secondCategory,
+ProductObject(..),
+ProductMorphism(..),
+ProductCategory(..),
+)
+where
+    import FiniteCategory.FiniteCategory
+    import Utils.CartesianProduct
+    import IO.PrettyPrint
+    
+    -- | Object in a product category.
+    data ProductObject o1 o2 = ProductObject o1 o2 deriving (Eq, Show, Ord)
+    
+    -- | Returns the first object of a product object.
+    firstObject :: ProductObject o1 o2 -> o1
+    firstObject (ProductObject o1 _) = o1
+    
+    -- | Returns the second object of a product object.
+    secondObject :: ProductObject o1 o2 -> o2
+    secondObject (ProductObject _ o2) = o2
+    
+    -- | Morphism in a product category.
+    data ProductMorphism m1 o1 m2 o2 = ProductMorphism m1 m2 deriving (Eq, Show, Ord)
+    
+    -- | Returns the first morphism of a product morphism.
+    firstMorphism :: ProductMorphism m1 o1 m2 o2 -> m1
+    firstMorphism (ProductMorphism m1 _) = m1
+    
+    -- | Returns the second morphism of a product morphism.
+    secondMorphism :: ProductMorphism m1 o1 m2 o2 -> m2
+    secondMorphism (ProductMorphism _ m2) = m2
+    
+    -- | Product category of two categories.
+    data ProductCategory c1 m1 o1 c2 m2 o2 = ProductCategory c1 c2 deriving (Eq, Show, Ord)
+
+    -- | Returns the first category of a product category.
+    firstCategory :: ProductCategory c1 m1 o1 c2 m2 o2 -> c1
+    firstCategory (ProductCategory c1 _) = c1
+    
+    -- | Returns the second category of a product category.
+    secondCategory :: ProductCategory c1 m1 o1 c2 m2 o2 -> c2
+    secondCategory (ProductCategory _ c2) = c2
+
+    instance (Morphism m1 o1, Morphism m2 o2) => Morphism (ProductMorphism m1 o1 m2 o2) (ProductObject o1 o2) where
+        source (ProductMorphism m1 m2) = ProductObject (source m1) (source m2)
+        target (ProductMorphism m1 m2) = ProductObject (target m1) (target m2)
+        (ProductMorphism g1 g2) @ (ProductMorphism f1 f2) = ProductMorphism (g1 @ f1) (g2 @ f2)
+                                                
+    instance (FiniteCategory c1 m1 o1, Morphism m1 o1,
+              FiniteCategory c2 m2 o2, Morphism m2 o2) =>
+              FiniteCategory (ProductCategory c1 m1 o1 c2 m2 o2) (ProductMorphism m1 o1 m2 o2) (ProductObject o1 o2) where
+        ob (ProductCategory c1 c2) = [ProductObject a b | a <- (ob c1), b <- (ob c2)]
+        identity (ProductCategory c1 c2) (ProductObject a b) = ProductMorphism (identity c1 a) (identity c2 b)
+        ar (ProductCategory c1 c2) (ProductObject s1 s2) (ProductObject t1 t2) = [ProductMorphism m1 m2 | m1 <- ar c1 s1 t1, m2 <- ar c2 s2 t2]
+        
+    instance (GeneratedFiniteCategory c1 m1 o1, Morphism m1 o1,
+              GeneratedFiniteCategory c2 m2 o2, Morphism m2 o2) =>
+              GeneratedFiniteCategory (ProductCategory c1 m1 o1 c2 m2 o2) (ProductMorphism m1 o1 m2 o2) (ProductObject o1 o2) where
+        genAr (ProductCategory c1 c2) (ProductObject s1 s2) (ProductObject t1 t2) = [ProductMorphism m1 m2 | m1 <- genAr c1 s1 t1, m2 <- genAr c2 s2 t2]
+        decompose (ProductCategory c1 c2) (ProductMorphism m1 m2) = [ProductMorphism d1 d2 | d1 <- decompoExtended1, d2 <- decompoExtended2]
+            where
+                decompo1 = decompose c1 m1
+                decompo2 = decompose c2 m2
+                decompoExtended1 = if ((length decompo1) < (length decompo2)) then (replicate ((length decompo2)-(length decompo1)) (identity c1 (target (head decompo1))))++decompo1 else decompo1
+                decompoExtended2 = if ((length decompo2) < (length decompo1)) then (replicate ((length decompo1)-(length decompo2)) (identity c2 (target (head decompo2))))++decompo2 else decompo2
+                
+    instance (PrettyPrintable o1, PrettyPrintable o2) => PrettyPrintable (ProductObject o1 o2) where
+        pprint (ProductObject a b) = "<"++(pprint a)++","++(pprint b)++">"
+        
+    
+    instance (PrettyPrintable m1, PrettyPrintable m2) => PrettyPrintable (ProductMorphism m1 o1 m2 o2) where
+        pprint (ProductMorphism f g) = "<"++(pprint f)++","++(pprint g)++">"
+ src/RandomCompositionGraph/RandomCompositionGraph.hs view
@@ -0,0 +1,126 @@+{-| Module  : FiniteCategories
+Description : Randomly generated composition graphs.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+This module provide functions to generate randomly composition graphs.
+It is an easy and fast way to generate a lot of finite categories.
+It can be used to test functions, to generate examples or to test hypothesis.
+-}
+
+module RandomCompositionGraph.RandomCompositionGraph 
+(
+    mkRandomCompositionGraph,
+    defaultMkRandomCompositionGraph
+)
+where
+    import FiniteCategory.FiniteCategory 
+    import CompositionGraph.CompositionGraph        (Graph(..), CGMorphism(..), CompositionLaw(..), CompositionGraph(..), Arrow(..), mkCompositionGraph, isGen, isComp)
+    import System.Random                            (RandomGen, uniformR)
+    import Data.Maybe                               (isNothing, fromJust)
+    import Utils.AssociationList
+    import Utils.Sample
+    import Utils.Tuple
+
+    -- | Find first order composites arrows in a composition graph.
+    compositeMorphisms :: (Eq a, Eq b, Show a) => CompositionGraph a b -> [CGMorphism a b]
+    compositeMorphisms c = [g @ f | f <- genArrows c, g <- genArFrom c (target f), not (elem (g @ f) (genAr c (source f) (target g)))]
+
+    -- | Merge two nodes.
+    mergeNodes :: (Eq a) => CompositionGraph a b -> a -> a -> CompositionGraph a b
+    mergeNodes cg@CompositionGraph{graph=g@(objs,ars),law=l} s t
+        | not (elem s objs) = error "mapped but not in rcg."
+        | not (elem t objs) = error "mapped to but not in rcg."
+        | s == t = cg
+        | otherwise = CompositionGraph {graph=(filter (/=s) objs,replaceArrow <$> ars), law=newLaw}
+        where
+            replace x = if x == s then t else x
+            replaceArrow (s1,t1,l1) = (replace s1, replace t1, l1)
+            newLaw = (\(k,v) -> (replaceArrow <$> k, replaceArrow <$> v)) <$> l
+    
+    -- | Merge two morphisms of a composition graph, the morphism mapped should be composite, the morphism mapped to should be a generator.
+    mergeMorphisms :: (Eq a, Eq b) => CompositionGraph a b -> CGMorphism a b -> CGMorphism a b -> CompositionGraph a b
+    mergeMorphisms cg@CompositionGraph{graph=g,law=l} s@CGMorphism{path=p1@(s1,rp1,t1),compositionLaw=l1} t@CGMorphism{path=p2@(s2,rp2,t2),compositionLaw=l2}
+        | (isGen s) = error "Generator at the start of a merge"
+        | (isComp t) = error "Composite at the end of a merge"
+        | s1 == t1 =  mergeNodes CompositionGraph{graph=g, law=newLaw} (source s) (source t)
+        | s1 == t2 = mergeNodes (mergeNodes CompositionGraph{graph=g, law=newLaw} (source s) (source t)) (target s) (source t)
+        | otherwise = mergeNodes (mergeNodes CompositionGraph{graph=g, law=newLaw} (source s) (source t)) (target s) (target t) where
+        newLaw = ((replaceArrow <$> rp1,replaceArrow <$> rp2):((\(k,v) -> (replaceArrow <$> k, replaceArrow <$> v)) <$> l))
+            where
+                replace x = if x == s1 then s2 else (if x == t1 then t2 else x)
+                replaceArrow (s3,t3,l3) = (replace s3, replace t3, l3)
+    
+    -- | Checks associativity of a composition graph.
+    checkAssociativity :: (Eq a, Eq b, Show a) => CompositionGraph a b -> Bool
+    checkAssociativity cg = foldr (&&) True [checkTriplet (f,g,h) | f <- genArrows cg, g <- genArFrom cg (target f), h <- genArFrom cg (target g)]
+        where
+            checkTriplet (f,g,h) = (h @ g) @ f == h @ (g @ f)
+        
+    -- | Find all composite arrows and try to map them to generating arrows. 
+    identifyCompositeToGen :: (RandomGen g, Eq a, Eq b, Show a) => CompositionGraph a b -> Int -> g -> (Maybe (CompositionGraph a b), g)
+    identifyCompositeToGen _ 0 rGen = (Nothing, rGen)
+    identifyCompositeToGen cg n rGen
+        | not (checkAssociativity cg) = (Nothing, rGen)
+        | null compositeMorphs = (Just cg, rGen)
+        | otherwise = if isNothing newCG then identifyCompositeToGen cg (n `div` 2) newGen2 else (newCG, newGen2)
+        where
+            compositeMorphs = compositeMorphisms cg
+            morphToMap = (head compositeMorphs)
+            (selectedGen,newGen1) = if (source morphToMap == target morphToMap) then pickOne [fs | obj <- ob cg, fs <- (genAr cg obj obj)] rGen else pickOne (genArrows cg) rGen
+            (newCG,newGen2) = identifyCompositeToGen (mergeMorphisms cg morphToMap selectedGen) n newGen1 
+            
+    -- | Algorithm described in `mkRandomCompositionGraph`.
+    monoidificationAttempt :: (RandomGen g, Eq a, Eq b, Show a) => CompositionGraph a b -> Int -> g -> (CompositionGraph a b, g, [a])
+    monoidificationAttempt cg p g = if isNothing result then (cg,finalGen,[]) else (fromJust result, finalGen, [s,t])
+        where
+            ([s,t],newGen) = if ((length (ob cg)) > 1) then sample (ob cg) 2 g else (ob cg ++ ob cg,g)
+            newCG = mergeNodes cg s t
+            (result,finalGen) = identifyCompositeToGen newCG p newGen
+    
+    -- | Initialize a composition graph with all arrows seperated.
+    initRandomCG :: Int -> CompositionGraph Int Int
+    initRandomCG n = CompositionGraph{graph=([0..n+n-1],[((i+i),(i+i+1), i) | i <- [0..n]]),law=[]}
+    
+    -- | Generates a random composition graph.
+    --
+    -- We use the fact that a category is a generalized monoid.
+    --
+    -- We try to create a composition law of a monoid greedily.
+    --
+    -- To get a category, we begin with a category with all arrows seperated and not composing with each other. 
+    -- It is equivalent to the monoid with an empty composition law.
+    --
+    -- Then, a monoidification attempt is the following algorihm :
+    --
+    -- 1. Pick two objects, merge them.
+    -- 2. While there are composite morphisms, try to merge them with generating arrows.
+    -- 3. If it fails, don't change the composition graph.
+    -- 4. Else return the new composition graph
+    -- 
+    -- A monoidification attempt takes a valid category and outputs a valid category, furthermore, the number of arrows is constant
+    -- and the number of objects is decreasing (not strictly).
+    mkRandomCompositionGraph :: (RandomGen g) => Int -- ^ Number of arrows of the random composition graph.
+                                              -> Int -- ^ Number of monoidification attempts, a bigger number will produce more morphisms that will compose but the function will be slower.
+                                              -> Int -- ^ Perseverance : how much we pursure an attempt far away to find a law that works, a bigger number will make the attemps more successful, but slower. (When in doubt put 4.)
+                                              -> g   -- ^ Random generator.
+                                              -> (CompositionGraph Int Int, g)
+    mkRandomCompositionGraph nbAr nbAttempts perseverance gen = attempt (initRandomCG nbAr) nbAttempts perseverance gen
+        where
+            attempt cg 0 _ gen = (cg, gen)
+            attempt cg n p gen = attempt newCG (n-1) p newGen
+                where
+                    (newCG, newGen,_) = (monoidificationAttempt cg p gen)
+    
+    -- | Creates a random composition graph with default random values.
+    --
+    -- The number of arrows will be in the interval [1, 20].
+    defaultMkRandomCompositionGraph  :: (RandomGen g) => g -> (CompositionGraph Int Int, g)
+    defaultMkRandomCompositionGraph g1 = mkRandomCompositionGraph nbArrows (min nbAttempts 20) 4 g3
+        where 
+            (nbArrows, g2) = uniformR (1,20) g1
+            (nbAttempts, g3) = uniformR (0,nbArrows+nbArrows) g2
+            
+ src/RandomDiagram/RandomDiagram.hs view
@@ -0,0 +1,45 @@+{-| Module  : FiniteCategories
+Description : Select a random diagram in a category.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+This module provide functions to generate random diagrams.
+It can be used to test functions, to generate examples or to test hypothesis.
+-}
+
+module RandomDiagram.RandomDiagram 
+(
+    mkRandomDiagram,
+    defaultMkRandomDiagram
+)
+where
+    import FiniteCategory.FiniteCategory
+    import CompositionGraph.CompositionGraph
+    import RandomCompositionGraph.RandomCompositionGraph
+    import System.Random                            (RandomGen, uniformR)
+    import Data.Maybe                               (isNothing, fromJust)
+    import Utils.Sample
+    import FunctorCategory.FunctorCategory
+    import Diagram.Diagram
+
+    -- | Choose a random diagram in the functor category of an index category and an image category.
+    mkRandomDiagram :: (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1,
+                        FiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2,
+                        RandomGen g) => c1 -> c2 -> g -> (Diagram c1 m1 o1 c2 m2 o2, g)
+    mkRandomDiagram index cat gen = pickOne (ob FunctorCategory{sourceCat=index, targetCat=cat}) gen
+    
+    
+    -- | Constructs two random composition graphs and choose a random diagram between the two.
+    defaultMkRandomDiagram  :: (RandomGen g) => g ->  (Diagram (CompositionGraph Int Int) (CGMorphism Int Int) Int (CompositionGraph Int Int) (CGMorphism Int Int) Int, g)
+    defaultMkRandomDiagram g1 = mkRandomDiagram cat1 cat2 g3
+        where 
+            (nbArrows1, g2) = uniformR (1,8) g1
+            (nbAttempts1, g3) = uniformR (0,nbArrows1+nbArrows1) g2
+            (cat1, g4) = mkRandomCompositionGraph nbArrows1 nbAttempts1 5 g3
+            (nbArrows2, g5) = uniformR (1,11-nbArrows1) g4
+            (nbAttempts2, g6) = uniformR (0,nbArrows2+nbArrows2) g5
+            (cat2, g7) = mkRandomCompositionGraph nbArrows2 nbAttempts2 5 g6
+            
+ src/Set/FinOrdSet.hs view
@@ -0,0 +1,96 @@+{-# LANGUAGE MultiParamTypeClasses #-}
+
+{-| Module  : FiniteCategories
+Description : The category of finite sets of elements you can order (it is optimized with the Data.Set type).
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Same as `FinOrdSet` but using Data.Set as objects, it is more optimized but needs its elements to be ordered.
+-}
+
+module Set.FinOrdSet
+(
+    -- * The morphism of the category : `FinOrdMap`
+    FinOrdMap(..),
+    -- * The category itself : `FinOrdSet`
+    FinOrdSet(..),
+    powerFinOrdSet
+)
+where
+    import  qualified   Data.Map                        as Map  (Map, (!), fromList, keys)
+    import  qualified   Data.Set                        as Set  (Set, fromList, toList, powerSet, null, size, findMin)
+    import              Data.List                               (intercalate, nub)
+    import              FiniteCategory.FiniteCategory           (FiniteCategory(..), GeneratedFiniteCategory(..), Morphism(..), bruteForceDecompose)
+    import              Control.Monad                           (filterM)
+    import              Utils.CartesianProduct                  ((|^|))
+    import              IO.PrettyPrint
+    
+    
+    -- | `FinOrdMap` is the morphism of the `FinOrdSet` category.
+    --
+    -- It is represented by a `Data.Map`. The domain is the list of /keys/.
+    -- We need to store the codomain of the map in order to differentiate different maps which would be the same if we couldn't compare codomains.
+    -- For example, @f : {1,2,3} -> {1,2,3}@ and @g : {1,2,3} -> {1,2,3,4}@ would have the same `Data.Map` but are different.
+    data FinOrdMap a = FinOrdMap {codomain :: Set.Set a, function :: Map.Map a a} deriving (Eq, Show)
+    
+    instance (Ord a) => Morphism (FinOrdMap a) (Set.Set a) where
+        (@) g f = FinOrdMap {codomain=codomain g, function=Map.fromList[(k,(function g)Map.!((function f) Map.! k))| k <- Map.keys (function f)]}
+        source = Set.fromList.(Map.keys).function
+        target = codomain        
+    
+    instance (PrettyPrintable a, Ord a) => PrettyPrintable (FinOrdMap a) where
+        pprint f = pprint (source f) ++ " -> " ++ pprint (target f) ++ "\n" ++ pprint (function f)
+    
+    -- | `FinOrdSet` stores the sets which constitutes its objects.
+    data (FinOrdSet a) = FinOrdSet {sets :: [Set.Set a]} deriving (Show)
+    
+    instance (Ord a) => FiniteCategory (FinOrdSet a) (FinOrdMap a) (Set.Set a) where
+        ob = nub.sets
+        identity c s 
+            | elem s (ob c) = FinOrdMap {codomain=s, function=Map.fromList [(o,o)| o <- (Set.toList s)]}
+            | otherwise = error("Trying to get identity of an object not in the Set category.")
+        ar c s t 
+            | Set.null s = [FinOrdMap {codomain=t, function=Map.fromList []}]
+            | Set.null t = []
+            | otherwise = (\x -> FinOrdMap {codomain=t, function=Map.fromList x}) <$> [zip domain i | i <- images] where
+                domain = Set.toList s
+                codomain = Set.toList t
+                images = (codomain |^| (length domain))
+                
+    instance (Ord a) => GeneratedFiniteCategory (FinOrdSet a) (FinOrdMap a) (Set.Set a) where
+        genAr c s t
+            | Set.null s = [FinOrdMap {codomain=t, function= Map.fromList []}]
+            | Set.null t = []
+            | Set.size s == 1 = [FinOrdMap {codomain=t, function=injectiv}] 
+            | Set.size t == 1 = [FinOrdMap {codomain=t, function=surjectiv}]
+            | s == t = nub $ (\m -> FinOrdMap {codomain=t, function=m}) <$> [transpose,rotate,project]           
+            | length s < length t = [FinOrdMap {codomain=t, function=injectiv}] 
+            | otherwise = [FinOrdMap {codomain=t, function=surjectiv}]  
+            where
+            domain = Set.toList s
+            codomain = Set.toList t
+            transpose = Map.fromList ([(domain !! 0, domain !! 1),(domain !! 1, domain !! 0)]++[(o,o) | o <- drop 2 domain])
+            rotatedDomain = (tail domain) ++ [(head domain)]
+            rotate = Map.fromList (zip domain rotatedDomain)                
+            project = Map.fromList ((domain !! 0, domain !! 1):[(o,o) | o <- tail domain])
+            injectiv = Map.fromList (zip domain codomain)
+            surjectiv = Map.fromList (zip domain ((replicate ((length s)-(length t)+1) (head codomain))++codomain))
+        
+        decompose = bruteForceDecompose
+
+    instance (Ord a) => Eq (FinOrdSet a) where
+        FinOrdSet {sets=ss1} == FinOrdSet {sets=ss2} = if ss1 == [] then ss2 == [] else (isIncluded ss1 ss2) && (isIncluded ss2 ss1)
+            where
+                isIncluded [] ss2 = True
+                isIncluded (s:ss1) ss2 = (elem s ss2) && (isIncluded ss1 ss2)
+                
+    instance (PrettyPrintable a) =>  PrettyPrintable (FinOrdSet a) where
+        pprint FinOrdSet {sets=ss} = "FinOrdSet of "++ pprint ss
+
+    -- | Returns the `FinOrdSet` category such that every subset of the set given is an object of the category.
+    powerFinOrdSet :: (Ord a) => Set.Set a -> FinOrdSet a
+    powerFinOrdSet x = FinOrdSet {sets = (Set.toList).(Set.powerSet) $ x}
+    
+ src/Set/FinSet.hs view
@@ -0,0 +1,203 @@+{-# LANGUAGE MultiParamTypeClasses #-}
+
+{-| Module  : FiniteCategories
+Description : The category of finite sets.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+The __FinSet__ category has as objects finite sets and as morphisms maps between them.
+It is a full subcategory of the __Set__ category.
+It is itself a large category (therefore not a finite one),
+we only construct finite subcategories of the mathematical infinite __FinSet__ category.
+`FinSet` is the type of full finite subcategories of __FinSet__.
+
+To instantiate it, use the `FinSet` constructor on a list of sets.
+
+For example, see Example.ExampleSet
+-}
+
+module Set.FinSet where
+    import              Data.List                               (intersect, nub, intercalate, subsequences)
+    import              Utils.SetList
+    import              Utils.AssociationList
+    import              FiniteCategory.FiniteCategory
+    import              Utils.CartesianProduct                  ((|^|))
+    import              IO.PrettyPrint
+    
+    import              Diagram.Diagram
+    import              ConeCategory.ConeCategory
+    import              UsualCategories.One
+    
+    -- | When constructing a set, the following rules should be respected :
+    --
+    -- - An elem is always a leaf construct.
+    --
+    -- - There should be no duplicate in a Collection.
+    --
+    -- - The root construct is always a Collection.
+    --
+    -- This set construction does not require the ord constraint.
+    data FinSet a =   Elem a
+                    | Collection [FinSet a]
+                    deriving (Show)
+    
+    instance (Eq a) => Eq (FinSet a) where
+        (Elem a) == (Elem b) = a == b
+        (Collection s1) == (Collection s2) = doubleInclusion s1 s2
+        _ == _ = False
+    
+    instance Functor FinSet where
+        fmap f (Elem a) = Elem (f a)
+        fmap f (Collection xs) = Collection (fmap f <$> xs)
+    
+    -- | Constructs the empty set.
+    emptyFinSet :: FinSet a
+    emptyFinSet = Collection []
+    
+    -- | Constructs a singleton set.
+    singleton :: a -> FinSet a
+    singleton x = Collection [Elem x]
+    
+    -- | Extract a list from a set.
+    toList :: FinSet a -> [FinSet a]
+    toList (Collection list) = list
+    
+    -- | Transforms a list of sets into a set.
+    fromList :: (Eq a) => [FinSet a] -> FinSet a
+    fromList xs = Collection $ nub xs
+    
+    -- | Union of two sets.
+    (|||) :: (Eq a) => FinSet a -> FinSet a -> FinSet a
+    (|||) (Collection l1) (Collection l2) = Collection $ nub (l1++l2)
+    
+    -- | Union of a list of sets.
+    union :: (Eq a) => [FinSet a] -> FinSet a
+    union sets = foldr (|||) emptyFinSet sets
+    
+    -- | Intersection of two sets.
+    (&&&) :: (Eq a) => FinSet a -> FinSet a -> FinSet a
+    (&&&) (Collection l1) (Collection l2) = Collection $ intersect l1 l2
+    
+    -- | Intersection of a list of sets.
+    intersection :: (Eq a) => [FinSet a] -> FinSet a
+    intersection [] = error "Cannot make an intersection of no set."
+    intersection sets = foldr1 (&&&) sets
+    
+    -- | Returns wether a set is in another one.
+    isIn :: (Eq a) => FinSet a -> FinSet a -> Bool
+    isIn e (Collection es) = elem e es
+    
+    -- | Returns wether a set is included in another one.
+    includedIn :: (Eq a) => FinSet a -> FinSet a -> Bool
+    includedIn (Collection l1) (Collection l2) = isIncludedIn l1 l2
+    
+    -- | Returns the size of a set.
+    card :: FinSet a -> Int
+    card (Collection xs) = length xs
+    
+    -- | Generalizes a set of @a@ so that it can contain elements of type @a@ or @b@. 
+    generalizeType :: FinSet a -> FinSet (Either a b)
+    generalizeType = fmap Left
+    
+    instance (PrettyPrintable a) => PrettyPrintable (FinSet a) where
+        pprint (Elem a) = pprint a
+        pprint (Collection elems) = "{"++ (intercalate "," (pprint <$> elems)) ++ "}"
+    
+    -- | `FinMap` is the morphism of the `FinSetCat` category.
+    --
+    -- We need to keep the codomain because it would not be present in a non-surjective map.
+    --
+    -- It is represented by an association list and a codomain.
+    data FinMap a = FinMap {  finMap :: (AssociationList (FinSet a) (FinSet a))
+                            , codomain :: (FinSet a)
+                           }
+                           deriving (Eq, Show)
+    
+    instance (Eq a) => Morphism (FinMap a) (FinSet a) where
+        (@) g f = FinMap {    finMap = [(k,((finMap g) !-! v)) | (k,v) <- (finMap f)]
+                            , codomain = (codomain g)
+                         }
+        source m = Collection $ nub (keys (finMap m))
+        target = codomain
+        
+    instance (PrettyPrintable a, Eq a) => PrettyPrintable (FinMap a) where
+        pprint f = pprint (source f) ++ " -> " ++ pprint (target f) ++ "\n" ++ pprint (finMap f)
+    
+    -- | `FinSetCat` is the type for the category of `FinSet`.
+    -- Its elements are the sets considered in the Set category.
+    data FinSetCat a = FinSetCat [FinSet a] deriving (Eq, Show)
+ 
+    instance (Eq a) => FiniteCategory (FinSetCat a) (FinMap a) (FinSet a) where
+        ob (FinSetCat xs) = xs
+        identity c s
+            | elem s (ob c) = FinMap{ finMap = [(e,e) | e <- toList s]
+                                    , codomain = s
+                                    }
+            | otherwise = error("Trying to get identity of an object not in the Set category.")
+        ar _ s t
+            | s == emptyFinSet = [FinMap{finMap=[],codomain=t}]
+            | t == emptyFinSet = []
+            | otherwise = (\x -> FinMap {codomain=t, finMap=x}) <$> [zip domain i | i <- images] where
+                domain = toList s
+                codomain = toList t
+                images = (codomain |^| (length domain))
+          
+    instance (Eq a) => GeneratedFiniteCategory (FinSetCat a) (FinMap a) (FinSet a) where
+        genAr _ s t
+            | s == emptyFinSet = [FinMap{finMap=[],codomain=t}]
+            | t == emptyFinSet = []
+            | card s == 1 = [FinMap {codomain=t, finMap=injectiv}] 
+            | card t == 1 = [FinMap {codomain=t, finMap=surjectiv}]
+            | s == t = nub $ (\m -> FinMap {codomain=t, finMap=m}) <$> [transpose,rotate,project]           
+            | card s < card t = [FinMap {codomain=t, finMap=injectiv}] 
+            | otherwise = [FinMap {codomain=t, finMap=surjectiv}]  
+            where
+            domain = toList s
+            codomain = toList t
+            transpose = [(domain !! 0, domain !! 1),(domain !! 1, domain !! 0)]++[(o,o) | o <- drop 2 domain]
+            rotatedDomain = (tail domain) ++ [(head domain)]
+            rotate = zip domain rotatedDomain             
+            project = (domain !! 0, domain !! 1):[(o,o) | o <- tail domain]
+            injectiv = zip domain codomain
+            surjectiv = zip domain ((replicate ((card s)-(card t)+1) (head codomain))++codomain)
+        
+        decompose = bruteForceDecompose
+
+    instance (PrettyPrintable a) => PrettyPrintable (FinSetCat a) where
+        pprint (FinSetCat xs) = "FinSetCat "++(pprint xs)
+
+    -- | Returns the `FinSet` category such that every subset of the set given is an object of the category.
+    powerFinSet :: FinSet a -> FinSet a
+    powerFinSet (Collection xs) = Collection (Collection <$> subsequences xs)
+                    
+    -- | Add a set to the target FinSetCat such that the given diagram has a limit. The diagram must not be the empty diagram from @0@ to @0@.
+    --
+    -- Returns an insertion functor from the previous set category to the new one, an updated diagram which has a limit, and the new limit object.
+    constructLimit :: (FiniteCategory c m o, Morphism m o, Eq a, Eq c, Eq m, Eq o) => Diagram c m o (FinSetCat a) (FinMap a) (FinSet a) -> (Diagram (FinSetCat a) (FinMap a) (FinSet a) (FinSetCat a) (FinMap a) (FinSet a), Diagram c m o (FinSetCat a) (FinMap a) (FinSet a), (FinSet a))
+    constructLimit diag = (insertionFunctor, newDiagram, newLimitObject)
+        where
+            cat@(FinSetCat sets) = tgt diag
+            singletonAlreadyHere = or $ (\s -> card s == 1) <$> sets
+            singleton2 = if singletonAlreadyHere 
+                            then    
+                                head [s | s <- sets, card s == 1] 
+                            else
+                                Collection [head sets] -- we make a singleton out of the first set
+            newSetCat = if singletonAlreadyHere
+                            then
+                                cat
+                            else
+                                FinSetCat (singleton2:sets)
+            newDiag = Diagram {src = src diag, tgt = newSetCat, omap = omap diag, mmap = mmap diag}
+            newLimitObject = Collection $ [(iterate (\x -> Collection [x]) singleton2) !! i | i <- [1..(length (conesOfApex newDiag singleton2))]]
+            newTargetCat = FinSetCat (newLimitObject:sets)
+            insertionFunctor = Diagram {src = cat, tgt = newTargetCat, omap = functToAssocList id (ob cat)
+                , mmap = functToAssocList id (arrows cat)}
+            newDiagram = insertionFunctor `composeDiag` diag
+                
+    -- | Generalizes a set category of @a@ so that it can contain elements of type @a@ or @b@. 
+    generalizeTypeSetCat :: FinSetCat a -> FinSetCat (Either a b)
+    generalizeTypeSetCat (FinSetCat xs) = FinSetCat $ (fmap Left) <$> xs
+ src/Subcategories/FreeSubcategory.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE UndecidableInstances, FlexibleInstances, MultiParamTypeClasses  #-}
+
+{-| Module  : FiniteCategories
+Description : Free subcategory generated by a subset of morphisms of a category C.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Free subcategory generated by a subset of morphisms of a category @C@.
+-}
+module Subcategories.FreeSubcategory
+(
+FreeSubcategory(..)
+)
+where
+    import FiniteCategory.FiniteCategory
+    import Data.List (nub)
+    import Utils.SetList
+    
+    -- | The free subcategory generated by a subset of morphisms of a category @C@.
+    data FreeSubcategory c m o = FreeSubcategory c [m]
+    
+    -- | Compose a list of morphisms with generator morphisms to generated new morphisms.
+    composeOnce :: (Morphism m o, Eq m, Eq o) => [m] -> [m] -> [m]
+    composeOnce m g = nub [m2 @ m1| m1 <- m, m2 <- g, (target m1) == (source m2)]
+    
+    -- | Compose a list of generator morphisms until it's useless.
+    composeUntilEnd :: (Morphism m o, Eq m, Eq o) => [m] -> [m]
+    composeUntilEnd g = composeRecursive g g
+        where composeRecursive ms g
+                | doubleInclusion nextStep ms = ms
+                | otherwise = composeRecursive nextStep g
+                where
+                    nextStep = composeOnce ms g
+    allArrows :: (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => FreeSubcategory c m o -> [m]
+    allArrows sc@(FreeSubcategory c morphs) = composeUntilEnd $ nub $ morphs++(identities sc)
+    
+    instance (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => FiniteCategory (FreeSubcategory c m o) m o where
+        ob (FreeSubcategory _ morphs) = nub $ [source m | m <- morphs]++[target m | m <- morphs]
+        identity (FreeSubcategory c morphs) obj = identity c obj
+        ar sc s t = filter (\x -> (source x) == s && (target x) == t) (allArrows sc)
+        arrows = allArrows
+        
+    instance (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => GeneratedFiniteCategory (FreeSubcategory c m o) m o where
+        genAr (FreeSubcategory _ morphs) s t = filter (\x -> (source x) == s && (target x) == t) morphs
+        decompose = bruteForceDecompose
+        genArrows (FreeSubcategory _ morphs) = morphs
+        
+ src/Subcategories/FullSubcategory.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE UndecidableInstances, FlexibleInstances, MultiParamTypeClasses  #-}
+
+{-| Module  : FiniteCategories
+Description : Full subcategory a category C.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Full subcategory a category C.
+-}
+module Subcategories.FullSubcategory
+(
+FullSubcategory(..)
+)
+where
+    import FiniteCategory.FiniteCategory
+    import Data.List (nub)
+    import Utils.SetList
+    import IO.PrettyPrint
+    
+    -- | The datatype for full subcategories of a given category containing given objects.
+    data FullSubcategory c m o = FullSubcategory c [o] deriving (Eq, Show)
+    
+    instance (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => FiniteCategory (FullSubcategory c m o) m o where
+        ob (FullSubcategory _ objs) = nub $ objs
+        identity (FullSubcategory c objs) obj = if elem obj objs then identity c obj else error "Cannot create identity of an object not in the category."
+        ar (FullSubcategory c objs) s t = if elem s objs && elem t objs then ar c s t else error "Cannot create morphisms between objects not in the category."
+        
+    instance (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => GeneratedFiniteCategory (FullSubcategory c m o) m o where
+        genAr = defaultGenAr
+        decompose = defaultDecompose
+        
+    instance (PrettyPrintable c, PrettyPrintable o) => PrettyPrintable (FullSubcategory c m o) where
+        pprint (FullSubcategory c o) = "Full subcategory of "++pprint c++" containing "++pprint o
+ src/Subcategories/Subcategory.hs view
@@ -0,0 +1,54 @@+{-# LANGUAGE UndecidableInstances, FlexibleInstances, MultiParamTypeClasses  #-}
+
+{-| Module  : FiniteCategories
+Description : A subcategory is the image of a faithful functor.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+A subcategory is the image of a faithful functor.
+-}
+
+module Subcategories.Subcategory where
+    import FiniteCategory.FiniteCategory
+    import Diagram.Diagram
+    import Utils.AssociationList
+    import Data.List (nub)
+    import Subcategories.FullSubcategory
+    
+    -- | The type to view a faithful diagram as a subcategory.
+    --
+    -- It is your responsability to check that the diagram is faithful.
+    data Subcategory c1 m1 o1 c2 m2 o2 = Subcategory (Diagram c1 m1 o1 c2 m2 o2)
+    
+    instance (FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1
+            , FiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2) => 
+            FiniteCategory (Subcategory c1 m1 o1 c2 m2 o2) m2 o2 where
+        ob (Subcategory diag) = nub $ ((omap diag) !-!) <$> (ob (src diag))
+        identity (Subcategory diag) o = identity (tgt diag) o
+        ar (Subcategory diag) s t = nub $ ((mmap diag) !-!) <$> ar (src diag) ((inverse.omap $ diag) !-! s) ((inverse.omap $ diag) !-! t)
+        
+    instance (GeneratedFiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1
+            , GeneratedFiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2) => 
+              GeneratedFiniteCategory (Subcategory c1 m1 o1 c2 m2 o2) m2 o2 where
+        genAr (Subcategory diag) s t = nub $ ((mmap diag) !-!) <$> genAr (src diag) ((inverse.omap $ diag) !-! s) ((inverse.omap $ diag) !-! t)
+        decompose (Subcategory diag) m = nub $ ((mmap diag) !-!) <$> decompose (src diag) ((inverse.mmap $ diag) !-! m)
+        
+    -- | Extracts a full and faithful diagram out of a faithful diagram.
+    fullDiagram :: (  FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1
+                    , FiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2) => 
+                    Diagram c1 m1 o1 c2 m2 o2 -> Diagram c1 m1 o1 (Subcategory c1 m1 o1 c2 m2 o2) m2 o2
+    fullDiagram diag = Diagram {src = src diag, tgt = Subcategory diag, omap = omap diag, mmap = mmap diag}
+    
+    -- | Strips the target of a diagram so that only given objects remain.
+    stripDiagram :: ( FiniteCategory c1 m1 o1, Morphism m1 o1, Eq m1, Eq o1
+                    , FiniteCategory c2 m2 o2, Morphism m2 o2, Eq m2, Eq o2) => 
+                      Diagram c1 m1 o1 c2 m2 o2 -> [o2] -> Diagram c1 m1 o1 (FullSubcategory c2 m2 o2) m2 o2
+    stripDiagram diag keep = Diagram {
+                            src = src diag,
+                            tgt = FullSubcategory (tgt diag) keep,
+                            omap = omap diag,
+                            mmap = mmap diag
+                                }
+ src/UsualCategories/DiscreteCategory.hs view
@@ -0,0 +1,54 @@+{-# LANGUAGE MultiParamTypeClasses #-}
+
+{-| Module  : FiniteCategories
+Description : A discrete category is a category with no morphism other than identities.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+A discrete category is a category with no morphism other than identities.
+-}
+
+module UsualCategories.DiscreteCategory 
+(
+    DiscreteObject(..),
+    DiscreteIdentity(..),
+    DiscreteCategory(..)
+)
+where
+    import          FiniteCategory.FiniteCategory
+    import          IO.PrettyPrint
+    
+    -- | A discrete object is just an usual object.
+    data DiscreteObject a = DiscreteObject a deriving (Eq, Show)
+    
+    instance (PrettyPrintable a) => PrettyPrintable (DiscreteObject a) where
+        pprint (DiscreteObject x) = pprint x
+    
+    -- | `DiscreteIdentity` is the morphism of the discrete category.
+    data DiscreteIdentity a = DiscreteIdentity a deriving (Eq, Show)
+    
+    instance (Eq a) => Morphism (DiscreteIdentity a) (DiscreteObject a) where
+        source (DiscreteIdentity x) = DiscreteObject x
+        target (DiscreteIdentity x) = DiscreteObject x
+        (@) = (\x y -> if x /= y then error "Composition of incompatible discrete morphisms" else x)
+    
+    instance (PrettyPrintable a) => PrettyPrintable (DiscreteIdentity a) where
+        pprint (DiscreteIdentity x) = "Id"++pprint x
+    
+    -- | The discrete category is just a list of objects.
+    data DiscreteCategory a = DiscreteCategory [a] deriving (Eq, Show)
+
+    instance (Eq a) => FiniteCategory (DiscreteCategory a) (DiscreteIdentity a) (DiscreteObject a) where
+        ob (DiscreteCategory objs) = DiscreteObject <$> objs
+        identity (DiscreteCategory objs) (DiscreteObject o) = if elem o objs then DiscreteIdentity o else error "Identity of an object not in the discrete category."
+        ar c x y = if x /= y then [] else [identity c x]
+        
+    instance (Eq a) => GeneratedFiniteCategory (DiscreteCategory a) (DiscreteIdentity a) (DiscreteObject a) where
+        genAr = defaultGenAr
+        decompose = defaultDecompose
+        
+    instance (PrettyPrintable a) => PrettyPrintable (DiscreteCategory a) where
+        pprint (DiscreteCategory xs) = "DiscreteCategory of " ++pprint xs
+ src/UsualCategories/Hat.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE MultiParamTypeClasses #-}
+
+{-| Module  : FiniteCategories
+Description : The Hat category contains two arrows coming from the same object.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+The Hat category contains two arrows coming from the same object.
+-}
+
+module UsualCategories.Hat
+(
+    HatOb(..),
+    HatAr(..),
+    Hat(..)
+)
+where
+    import          FiniteCategory.FiniteCategory
+    import          IO.PrettyPrint
+    
+    -- | Object of the Hat category.
+    data HatOb = A | B | C deriving (Eq, Show)
+    
+    -- | Morphism of the Hat category.
+    data HatAr = IdA | IdB | IdC | F | G deriving (Eq, Show)
+    
+    -- | The Hat category.
+    data Hat = Hat deriving (Eq, Show)
+    
+    instance Morphism HatAr HatOb where
+        source IdA = A
+        source IdB = B
+        source IdC = C
+        source _ = A
+        target IdA = A
+        target IdB = B
+        target IdC = C
+        target F = B
+        target G = C
+        (@) IdA IdA = IdA
+        (@) F IdA = F
+        (@) G IdA = G
+        (@) IdB IdB = IdB
+        (@) IdC IdC = IdC
+        (@) IdB F = F
+        (@) IdC G = G
+    
+    instance FiniteCategory Hat HatAr HatOb where
+        ob = const [A,B,C]
+        identity _ A = IdA
+        identity _ B = IdB
+        identity _ C = IdC
+        ar _ A A = [IdA]
+        ar _ B B = [IdB]
+        ar _ C C = [IdC]
+        ar _ A B = [F]
+        ar _ A C = [G]
+        ar _ _ _ = []
+        
+    instance GeneratedFiniteCategory Hat HatAr HatOb where
+        genAr = defaultGenAr
+        decompose = defaultDecompose
+        
+    instance PrettyPrintable HatOb where
+        pprint = show
+        
+    instance PrettyPrintable HatAr where
+        pprint = show
+    
+    instance PrettyPrintable Hat where
+        pprint = show
+ src/UsualCategories/One.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE MultiParamTypeClasses #-}
+
+{-| Module  : FiniteCategories
+Description : The __1__ category contains a unique object and its identity.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+The __1__ category contains a unique object and its identity.
+-}
+
+module UsualCategories.One 
+(
+    One(..)
+)
+where
+    import          FiniteCategory.FiniteCategory
+    import          IO.PrettyPrint
+    
+    -- | A type that serves the purpose of being the __1__ category, its object and its identity.
+    data One = One deriving (Eq, Show)
+    
+    instance Morphism One One where
+        source One = One
+        target One = One
+        (@) = const.const $ One
+    
+    instance FiniteCategory One One One where
+        ob = const [One]
+        identity = const.id
+        ar = const.const.const $ [One]
+        
+    instance GeneratedFiniteCategory One One One where
+        genAr = defaultGenAr
+        decompose = defaultDecompose
+        
+    instance PrettyPrintable One where
+        pprint One = "1"
+ src/UsualCategories/Parallel.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE MultiParamTypeClasses #-}
+
+{-| Module  : FiniteCategories
+Description : The parallel category contains two parallel arrows.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+The parallel category contains two objects `A` and `B` and two morphisms @`F` : `A` -> `B`@ and @`G` : `A` -> `B`@.
+-}
+
+module UsualCategories.Parallel 
+(
+    ParallelOb(..),
+    ParallelAr(..),
+    Parallel(..)
+)
+where
+    import          FiniteCategory.FiniteCategory
+    import          IO.PrettyPrint
+    
+    -- | Object of the parallel category.
+    data ParallelOb = A | B deriving (Eq, Show)
+    
+    -- | Morphism of the parallel category.
+    data ParallelAr = IdA | IdB | F | G deriving (Eq, Show)
+    
+    -- | The parallel category.
+    data Parallel = Parallel deriving (Eq, Show)
+    
+    instance Morphism ParallelAr ParallelOb where
+        source IdA = A
+        source IdB = B
+        source _ = A
+        target IdA = A
+        target IdB = B
+        target _ = B
+        (@) IdA IdA = IdA
+        (@) F IdA = F
+        (@) G IdA = G
+        (@) IdB IdB = IdB
+        (@) IdB F = F
+        (@) IdB G = G
+    
+    instance FiniteCategory Parallel ParallelAr ParallelOb where
+        ob = const [A,B]
+        identity _ A = IdA
+        identity _ B = IdB
+        ar _ A A = [IdA]
+        ar _ A B = [F,G]
+        ar _ B B = [IdB]
+        ar _ _ _ = []
+        
+    instance GeneratedFiniteCategory Parallel ParallelAr ParallelOb where
+        genAr = defaultGenAr
+        decompose = defaultDecompose
+        
+    instance PrettyPrintable ParallelOb where
+        pprint = show
+        
+    instance PrettyPrintable ParallelAr where
+        pprint = show
+    
+    instance PrettyPrintable Parallel where
+        pprint = show
+ src/UsualCategories/Square.hs view
@@ -0,0 +1,101 @@+{-# LANGUAGE MultiParamTypeClasses #-}
+
+{-| Module  : FiniteCategories
+Description : The square category contains 4 generating arrows forming a square.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+The square category contains 4 generating arrows forming a square.
+-}
+
+module UsualCategories.Square
+(
+    SquareOb(..),
+    SquareAr(..),
+    Square(..)
+)
+where
+    import          FiniteCategory.FiniteCategory
+    import          IO.PrettyPrint
+    
+    -- | Object of the Square category.
+    data SquareOb = A | B | C | D deriving (Eq, Show)
+    
+    -- | Morphism of the Square category.
+    data SquareAr = IdA | IdB | IdC | IdD | F | G | H | I | FH | GI deriving (Eq, Show)
+    
+    -- | The Square category.
+    data Square = Square deriving (Eq, Show)
+    
+    instance Morphism SquareAr SquareOb where
+        source IdA = A
+        source IdB = B
+        source IdC = C
+        source IdD = D
+        source F = A
+        source G = A
+        source H = B
+        source I = C
+        source FH = A
+        source GI = A
+        target IdA = A
+        target IdB = B
+        target IdC = C
+        target IdD = D
+        target F = B
+        target G = C
+        target H = D
+        target I = D
+        target FH = D
+        target GI = D
+        (@) IdA IdA = IdA
+        (@) F IdA = F
+        (@) G IdA = G
+        (@) FH IdA = FH
+        (@) GI IdA = GI
+        (@) IdB IdB = IdB
+        (@) H IdB = H
+        (@) IdC IdC = IdC
+        (@) I IdC = I
+        (@) IdD IdD = IdD
+        (@) IdB F = F
+        (@) H F = FH
+        (@) IdC G = G
+        (@) I G = GI
+        (@) IdD H = H
+        (@) IdD I = I
+        (@) IdD FH = FH
+        (@) IdD GI = GI
+        
+    instance FiniteCategory Square SquareAr SquareOb where
+        ob = const [A,B,C,D]
+        identity _ A = IdA
+        identity _ B = IdB
+        identity _ C = IdC
+        identity _ D = IdD
+        ar _ A A = [IdA]
+        ar _ A B = [F]
+        ar _ A C = [G]
+        ar _ A D = [FH,GI]
+        ar _ B B = [IdB]
+        ar _ B D = [H]
+        ar _ C C = [IdC]
+        ar _ C D = [I]
+        ar _ D D = [IdD]
+        ar _ _ _ = []
+        
+    instance GeneratedFiniteCategory Square SquareAr SquareOb where
+        genAr = defaultGenAr
+        decompose = defaultDecompose
+        
+    instance PrettyPrintable SquareOb where
+        pprint = show
+        
+    instance PrettyPrintable SquareAr where
+        pprint = show
+    
+    instance PrettyPrintable Square where
+        pprint = show
+ src/UsualCategories/Three.hs view
@@ -0,0 +1,84 @@+{-# LANGUAGE MultiParamTypeClasses #-}
+
+{-| Module  : FiniteCategories
+Description : The __3__ category contains three object `A`, `B` and `C` and three morphisms @`F` : `A` -> `B`@, @`G` : `B` -> `C`@, @`G`*`F` : `A` -> `C`@.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+The __3__ category contains three object `A`, `B` and `C` and three morphisms @`F` : `A` -> `B`@, @`G` : `B` -> `C`@, @`G`*`F` : `A` -> `C`@ (and of course three identities).
+-}
+
+module UsualCategories.Three 
+(
+    ThreeOb(..),
+    ThreeAr(..),
+    Three(..)
+)
+where
+    import          FiniteCategory.FiniteCategory
+    import          IO.PrettyPrint
+    
+    -- | Object of the __3__ category.
+    data ThreeOb = A | B | C deriving (Eq, Show)
+    
+    -- | Morphism of the __3__ category.
+    data ThreeAr = IdA | IdB | IdC | F | G | GF deriving (Eq,Show)
+    
+    -- | The __3__ category.
+    data Three = Three deriving (Eq,Show)
+    
+    instance Morphism ThreeAr ThreeOb where
+        source IdA = A
+        source IdB = B
+        source IdC = C
+        source F = A
+        source G = B
+        source GF = A
+        target IdA = A
+        target IdB = B
+        target IdC = C
+        target F = B
+        target G = C
+        target GF = C
+        (@) IdA IdA = IdA
+        (@) F IdA = F
+        (@) GF IdA = GF
+        (@) IdB IdB = IdB
+        (@) G IdB = G
+        (@) IdC IdC = IdC
+        (@) IdB F = F
+        (@) G F = GF
+        (@) IdC G = G
+        (@) IdC GF = GF
+        (@) x y = error ("Invalid composition of ThreeMorph : "++show x++" * "++show y)
+    
+    instance FiniteCategory Three ThreeAr ThreeOb where
+        ob = const [A,B,C]
+        identity _ A = IdA
+        identity _ B = IdB
+        identity _ C = IdC
+        ar _ A A = [IdA]
+        ar _ A B = [F]
+        ar _ A C = [GF]
+        ar _ B B = [IdB]
+        ar _ B C = [G]
+        ar _ C C = [IdC]
+        ar _ _ _ = []
+        
+    instance GeneratedFiniteCategory Three ThreeAr ThreeOb where
+        genAr _ A C = []
+        genAr c x y = defaultGenAr c x y
+        decompose _ GF = [G,F]
+        decompose c m = defaultDecompose c m
+        
+    instance PrettyPrintable ThreeOb where
+        pprint = show
+        
+    instance PrettyPrintable ThreeAr where
+        pprint = show
+    
+    instance PrettyPrintable Three where
+        pprint = show
+ src/UsualCategories/Two.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE MultiParamTypeClasses #-}
+
+{-| Module  : FiniteCategories
+Description : The __2__ category contains two object `A` and `B` and a morphism @`F` : `A` -> `B`@.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+The __2__ category contains two object `A` and `B` and a morphism @f : `A` -> `B`@ (and of course two identities).
+-}
+
+module UsualCategories.Two 
+(
+    TwoOb(..),
+    TwoAr(..),
+    Two(..)
+)
+where
+    import          FiniteCategory.FiniteCategory
+    import          IO.PrettyPrint
+    
+    -- | Object of the __2__ category.
+    data TwoOb = A | B deriving (Eq, Show)
+    
+    -- | Morphism of the __2__ category.
+    data TwoAr = IdA | IdB | F deriving (Eq,Show)
+    
+    -- | The __2__ category.
+    data Two = Two deriving (Eq,Show)
+    
+    instance Morphism TwoAr TwoOb where
+        source IdA = A
+        source IdB = B
+        source F = A
+        target IdA = A
+        target IdB = B
+        target F = B
+        (@) IdA IdA = IdA
+        (@) IdB IdB = IdB
+        (@) F IdA = F
+        (@) IdB F = F
+        (@) x y = error ("Invalid composition of TwoMorph : "++show x++" * "++show y)
+    
+    instance FiniteCategory Two TwoAr TwoOb where
+        ob = const [A,B]
+        identity _ A = IdA
+        identity _ B = IdB
+        ar _ A A = [IdA]
+        ar _ A B = [F]
+        ar _ B B = [IdB]
+        ar _ _ _ = []
+        
+    instance GeneratedFiniteCategory Two TwoAr TwoOb where
+        genAr = defaultGenAr
+        decompose = defaultDecompose
+        
+    instance PrettyPrintable TwoOb where
+        pprint = show
+        
+    instance PrettyPrintable TwoAr where
+        pprint = show
+        
+    instance PrettyPrintable Two where
+        pprint = show
+    
+ src/UsualCategories/V.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE MultiParamTypeClasses #-}
+
+{-| Module  : FiniteCategories
+Description : The V category contains two arrows pointing to the same object.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+The V category contains two arrows pointing to the same object.
+-}
+
+module UsualCategories.V 
+(
+    VOb(..),
+    VAr(..),
+    V(..)
+)
+where
+    import          FiniteCategory.FiniteCategory
+    import          IO.PrettyPrint
+    
+    -- | Object of the V category.
+    data VOb = A | B | C deriving (Eq, Show)
+    
+    -- | Morphism of the V category.
+    data VAr = IdA | IdB | IdC | F | G deriving (Eq, Show)
+    
+    -- | The V category.
+    data V = V deriving (Eq, Show)
+    
+    instance Morphism VAr VOb where
+        source IdA = A
+        source IdB = B
+        source IdC = C
+        source F = A
+        source G = B
+        target IdA = A
+        target IdB = B
+        target IdC = C
+        target _ = C
+        (@) IdA IdA = IdA
+        (@) F IdA = F
+        (@) IdB IdB = IdB
+        (@) G IdB = G
+        (@) IdC F = F
+        (@) IdC G = G
+        (@) IdC IdC = IdC
+    
+    instance FiniteCategory V VAr VOb where
+        ob = const [A,B,C]
+        identity _ A = IdA
+        identity _ B = IdB
+        identity _ C = IdC
+        ar _ A A = [IdA]
+        ar _ A C = [F]
+        ar _ B B = [IdB]
+        ar _ B C = [G]
+        ar _ C C = [IdC]
+        ar _ _ _ = []
+        
+    instance GeneratedFiniteCategory V VAr VOb where
+        genAr = defaultGenAr
+        decompose = defaultDecompose
+        
+    instance PrettyPrintable VOb where
+        pprint = show
+        
+    instance PrettyPrintable VAr where
+        pprint = show
+    
+    instance PrettyPrintable V where
+        pprint = show
+ src/UsualCategories/Zero.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE MultiParamTypeClasses #-}
+
+{-| Module  : FiniteCategories
+Description : The __0__ category contains no object and no morphism.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+The __0__ category contains no object and no morphism.
+-}
+
+module UsualCategories.Zero 
+(
+    Zero(..)
+)
+where
+    import          FiniteCategory.FiniteCategory
+    import          IO.PrettyPrint
+    
+    -- | The __0__ category.
+    data Zero = Zero deriving (Eq, Show)
+    
+    instance Morphism Zero Zero where
+        source _ = error "No morphism in the zero category."
+        target _ = error "No morphism in the zero category."
+        (@) _ _ = error "No morphism in the zero category."
+    
+    instance FiniteCategory Zero Zero Zero where
+        ob = const []
+        identity _ _ = error "No object in the zero category."
+        ar = const.const.const $ []
+        
+    instance GeneratedFiniteCategory Zero Zero Zero where
+        genAr = ar
+        decompose _ _ = error "No morphism in the zero category."
+        
+    instance PrettyPrintable Zero where
+        pprint = show
+ src/Utils/AssociationList.hs view
@@ -0,0 +1,108 @@+{-| Module  : FiniteCategories
+Description : The type for association lists.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+The type for association lists.
+
+It is used when the 'Ord' constraint of `Data.Map` is too restrictive.
+-}
+
+module Utils.AssociationList
+(
+    AssociationList,
+    keys,
+    values,
+    (!-),
+    (!-!),
+    (!-?),
+    (!-.),
+    mkAssocListIdentity,
+    enumAssocLists,
+    functToAssocList,
+    assocListToFunct,
+    inverse,
+    removeKey,
+    removeValue,
+)
+where
+    import Utils.CartesianProduct
+    import Data.Tuple (swap)
+    
+    -- | The type of association lists (a list of couples).
+    type AssociationList a b = [(a, b)]
+    
+    -- | Returns the keys of the association list.
+    keys :: (AssociationList a b) -> [a]
+    keys = fmap fst
+    
+    -- | Returns the values of the association list.
+    values :: (AssociationList a b) -> [b]
+    values = fmap snd
+    
+    -- | If the key is in the association list, returns Just the value associated, otherwise Nothing.
+    --
+    -- Same as lookup in `Data.Map`.
+    (!-) :: (Eq a) => a -> (AssociationList a b) -> Maybe b
+    (!-) _ [] = Nothing
+    (!-) k ((a,b):xs)
+        | a == k = Just b
+        | otherwise = k !- xs
+        
+    -- | If the key is in the association list, returns the value associated, otherwise throws an error.
+    --
+    -- Same as (!) in `Data.Map`.
+    (!-!) :: (Eq a) => (AssociationList a b) -> a -> b
+    (!-!) [] _ = error "Key not in association list."
+    (!-!) ((a,b):xs) k
+        | a == k = b
+        | otherwise = xs !-! k
+      
+    -- | If the key is in the association list, returns the value associated, otherwise returns a default value.
+    --
+    -- Same as /findWithDefault/ in `Data.Map`.      
+    (!-?) :: (Eq a) => b -> a -> (AssociationList a b) -> b
+    (!-?) d _ [] = d
+    (!-?) d k ((a,b):xs)
+        | a == k = b
+        | otherwise = (!-?) d k xs
+                               
+    -- | Composition of association lists.
+    (!-.) :: (Eq a, Eq b) => (AssociationList b c) -> (AssociationList a b) -> (AssociationList a c)
+    (!-.) al2 al1 = [(k, al2 !-! (al1 !-! k)) | k <- keys al1, elem (al1 !-! k) (keys al2)]
+    
+    -- | Constructs the identity association list of a list of values.
+    -- 
+    -- For example, @ mkAssocListIdentity [1,2,3] = [(1,1),(2,2),(3,3)]@
+    mkAssocListIdentity :: [a] -> AssociationList a a
+    mkAssocListIdentity xs = [(o,o) | o <- xs]
+    
+    -- | Enumerates all association lists possible between a domain and a codomain.
+    enumAssocLists :: [a] -> [b] -> [AssociationList a b]
+    enumAssocLists dom codom = [zip dom im | im <- (codom |^| (length dom))]
+    
+    -- | Transforms a function and a domain into an association list.
+    functToAssocList :: (a -> b) -> [a] -> (AssociationList a b)
+    functToAssocList f d = [(o, f o) | o <- d]
+    
+    -- | Transforms an association list to a function.
+    assocListToFunct :: (Eq a) => (AssociationList a b) -> a -> b
+    assocListToFunct [] _ = error "Can't transform an empty list into a function."
+    assocListToFunct ((k,v):xs) x
+        | k == x = v
+        | otherwise = assocListToFunct xs x
+        
+    -- | Inverse of an association list
+    inverse :: (AssociationList a b) -> (AssociationList b a)
+    inverse kvs = swap <$> kvs
+    
+    -- | Remove all couples with a certain key
+    removeKey :: (Eq a) => (AssociationList a b) -> a -> (AssociationList a b)
+    removeKey al key = [c | c@(k,_) <- al, k /= key]
+    
+    -- | Remove all couples with a certain value
+    removeValue :: (Eq b) => (AssociationList a b) -> b -> (AssociationList a b)
+    removeValue al value = [c | c@(_,v) <- al, v /= value]
+ src/Utils/CartesianProduct.hs view
@@ -0,0 +1,38 @@+{-| Module  : FiniteCategories
+Description : Simple functions to compute cartesian products of finite lists.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Simple functions to compute cartesian products of finite lists.
+-}
+
+module Utils.CartesianProduct
+(
+    cartesianProduct,
+    cartesianPower,
+    (|*|),
+    (|^|)
+)
+where
+    import Data.List (replicate)
+
+    -- | Returns the cartesian product of the finite lists.
+    --
+    -- cartesianProduct [A,B,C,...] = A x B x C x ...
+    cartesianProduct :: [[a]] -> [[a]]
+    cartesianProduct [] = [[]]
+    cartesianProduct (x:xs) = concat ((\l -> [e:l | e <- x]) <$> (cartesianProduct xs))
+    
+    -- | Returns the cartesian product of two lists
+    (|*|) :: [a] -> [a] -> [[a]]
+    x |*| y = cartesianProduct [x,y]
+
+    -- | Returns the cartesian product of a list by itself /k/ times.
+    cartesianPower :: [a] -> Int -> [[a]]
+    cartesianPower l k = cartesianProduct $ replicate k l
+    
+    -- | Infix alias for `cartesianPower`
+    (|^|) = cartesianPower
+ src/Utils/EnumerateMaps.hs view
@@ -0,0 +1,23 @@+{-| Module  : FiniteCategories
+Description : Enumerate all maps between two lists.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Enumerate all maps between two lists.
+-}
+module Utils.EnumerateMaps
+(
+    enumMaps
+)
+where
+    import Utils.CartesianProduct
+    import Utils.AssociationList
+    
+    -- | Returns all association lists from a domain to a codomain.
+    enumMaps :: [a] -- ^ Domain.
+             -> [b] -- ^ Codomain.
+             -> [AssociationList a b] -- ^ All association lists from domain to codomain.
+    enumMaps dom codom = zip dom <$> codom |^| (length dom)
+ src/Utils/Sample.hs view
@@ -0,0 +1,38 @@+{-| Module  : FiniteCategories
+Description : Sample randomly a list.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Sample randomly a list.
+-}
+
+module Utils.Sample 
+(
+    pickOne,
+    sample
+)
+where
+    import System.Random                            (RandomGen, uniformR)
+    
+    -- | Pick one element of a list randomly.
+    pickOne :: (RandomGen g) => [a] -> g -> (a,g)
+    pickOne [] g = error "pickOne in an empty list."
+    pickOne l g = ((l !! index),newGen) where
+        (index,newGen) = (uniformR (0,(length l)-1) g)
+        
+    listWithoutNthElem :: [a] -> Int -> [a]
+    listWithoutNthElem [] _ = []
+    listWithoutNthElem (x:xs) 0 = xs
+    listWithoutNthElem (x:xs) k = x:(listWithoutNthElem xs (k-1))
+        
+    -- | Sample /n/ elements of a list randomly.
+    sample :: (RandomGen g) => [a] -> Int -> g -> ([a],g)
+    sample _ 0 g = ([],g)
+    sample [] k g = error "Sample size bigger than the list size."
+    sample l n g = ((l !! index):rest,finalGen) where
+        (index,newGen) = (uniformR (0,(length l)-1) g)
+        new_l = listWithoutNthElem l index
+        (rest,finalGen) = sample new_l (n-1) newGen
+ src/Utils/SetList.hs view
@@ -0,0 +1,34 @@+{-| Module  : FiniteCategories
+Description : Utilitary functions for sets with list as underlying representation.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Utilitary functions for sets with list as underlying representation.
+
+It has the advantage of not requiring the Ord typeclass at all.
+-}
+
+module Utils.SetList
+(
+    isIncludedIn,
+    doubleInclusion,
+    powerList
+) where
+    -- | Returns a boolean indicating if the set of elements of a list are included in an another.
+    isIncludedIn :: (Eq a) => [a] -> [a] -> Bool
+    [] `isIncludedIn` _ = True
+    (x:xs) `isIncludedIn` l2
+        | x `elem` l2 = xs `isIncludedIn` l2
+        | otherwise = False
+        
+    -- | Returns a boolean indicating if the set of elements of two lists are equal.
+    doubleInclusion :: (Eq a) => [a] -> [a] -> Bool
+    l1 `doubleInclusion` l2 = (l1 `isIncludedIn` l2) && (l2 `isIncludedIn` l1)
+    
+    -- | Returns the list of all sublists of a list.
+    powerList :: (Eq a) => [a] -> [[a]]
+    powerList [] = [[]]
+    powerList (x:xs) = (powerList xs) ++ ((x:) <$> (powerList xs))
+ src/Utils/Tuple.hs view
@@ -0,0 +1,34 @@+{-| Module  : FiniteCategories
+Description : Utilitary functions for tuples.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Utilitary functions for tuples.
+-}
+
+module Utils.Tuple
+(
+fst3,
+snd3,
+trd3,
+uncurry3
+)
+where
+    -- | Returns the first element of a triplet.
+    fst3 :: (a,b,c) -> a
+    fst3 (x,_,_) = x
+    
+    -- | Returns the second element of a triplet.
+    snd3 :: (a,b,c) -> b
+    snd3 (_,x,_) = x
+    
+    -- | Returns the third element of a triplet.
+    trd3 :: (a,b,c) -> c
+    trd3 (_,_,x) = x
+    
+    -- | Uncurry 3 arguments.
+    uncurry3 :: (a -> b -> c -> d) -> (a,b,c) -> d
+    uncurry3 f (a,b,c) = f a b c
+ src/YonedaEmbedding/YonedaEmbedding.hs view
@@ -0,0 +1,69 @@+-- {-# LANGUAGE FlexibleContexts, MultiParamTypeClasses #-}
+
+{-| Module  : FiniteCategories
+Description : The Yoneda embedding of a category.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+The Yoneda embedding of a category.
+-}
+
+module YonedaEmbedding.YonedaEmbedding where
+    import FiniteCategory.FiniteCategory
+    import FunctorCategory.FunctorCategory
+    import Diagram.Diagram
+    import OppositeCategory.OppositeCategory
+    import Set.FinSet
+    import Utils.AssociationList
+    import Subcategories.Subcategory
+    import Currying.Currying
+    import OppositeCategory.OppositeCategory
+    import Limit.Limit
+    import ConeCategory.ConeCategory
+    import DiagonalFunctor.DiagonalFunctor
+    import Utils.Tuple
+    
+    import IO.PrettyPrint
+    
+    -- | A presheaf on a category @C@ is a diagram from @C^op@ to __Set__.
+    type PreSheaf c m o = Diagram (OppositeCategory c m o) (OppositeMorphism m o) o (FinSetCat m) (FinMap m) (FinSet m)
+    
+    -- | Natural transformation between presheaves.
+    type PreSheavesNatTransfo c m o = NaturalTransformation (OppositeCategory c m o) (OppositeMorphism m o) o (FinSetCat m) (FinMap m) (FinSet m)
+    
+    -- | The type of the category of presheaves.
+    type PreSheavesCategory c m o = FunctorCategory (OppositeCategory c m o) (OppositeMorphism m o) o (FinSetCat m) (FinMap m) (FinSet m)
+    
+    -- | Returns the presheaf category generated by a Yoneda embedding and an insertion functor full and faithful.
+    yonedaEmbedding :: (FiniteCategory c m o, Morphism m o, Eq m, Eq o) => c -> (PreSheavesCategory c m o, Diagram c m o (PreSheavesCategory c m o) (PreSheavesNatTransfo c m o) (PreSheaf c m o))
+    yonedaEmbedding cat = (presheavesCat, functor)
+        where
+            hom x = fromList $ fromList <$> (\s -> Elem <$> ar cat s x) <$> (ob cat)
+            omapPresheaf x s = fromList $ Elem <$> ar cat s x
+            mmapPresheaf x m = FinMap{codomain = omapPresheaf x (target m)
+                                    , finMap = zip (toList (omapPresheaf x (source m))) ((\f -> fmap (@ (opOpMorph m)) f) <$> (toList (omapPresheaf x (source m))))}
+            presheaf x = Diagram {    src = Op cat
+                                    , tgt = FinSetCat $ toList $ union $ hom <$> ob cat
+                                    , omap = functToAssocList (omapPresheaf x) (ob (Op cat))
+                                    , mmap = functToAssocList (mmapPresheaf x) (arrows (Op cat))}
+                                        
+            ntFromMorph m o = FinMap {codomain = (omap $ presheaf (target m)) !-! o
+                                    , finMap = zip (toList domain) (toList postcom) }
+                where
+                    domain = (omap $ presheaf (source m)) !-! o
+                    postcom = (m @) `fmap` domain
+            mmapFunctor m = NaturalTransformation {   srcNT = presheaf (source m)
+                                                    , tgtNT = presheaf (target m)
+                                                    , component = ntFromMorph m}
+                                                        
+            presheavesCat = FunctorCategory { sourceCat = Op cat
+                                            , targetCat = FinSetCat $ concat (toList <$> (hom <$> ob cat))}
+            functor = Diagram {   src = cat
+                                , tgt = presheavesCat
+                                , omap = functToAssocList presheaf (ob cat)
+                                , mmap = functToAssocList mmapFunctor (arrows cat)
+                              }
+                              
+ test/ExampleAdjunction/ExampleAdjunction.hs view
@@ -0,0 +1,44 @@+{-| Module  : FiniteCategories
+Description : An example of adjunction.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of adjunction.
+-}
+module ExampleAdjunction.ExampleAdjunction
+(
+    main
+)
+where
+    import              ExportGraphViz.ExportGraphViz          (catToPdf,genToPdf, diagToPdf, diagToPdf2, natToPdf)
+    import              Diagram.Diagram
+    import              Limit.Limit
+    import              UsualCategories.DiscreteCategory
+    import              Utils.AssociationList
+    import              CompositionGraph.CompositionGraph
+    import              IO.Parsers.Lexer
+    import              IO.Parsers.SafeCompositionGraph
+    import              IO.Parsers.SafeCompositionGraphFunctor
+    import              FunctorCategory.FunctorCategory
+    import              FiniteCategory.FiniteCategory
+    import              ConeCategory.ConeCategory
+    
+    -- | Export the categories defined above as pdf with GraphViz.
+    main = do
+        putStrLn "Start of ExampleAdjunction"
+        cg <- readSCGFile "test/ExampleAdjunction/ExampleAdjunction.scg"
+        catToPdf cg "OutputGraphViz/Examples/Adjunction/category"
+        diag1 <- readFSCGFile "test/ExampleAdjunction/ExampleAdjunctionDiag1.fscg"
+        diagToPdf2 diag1 "OutputGraphViz/Examples/Adjunction/diag1"
+        diag2 <- readFSCGFile "test/ExampleAdjunction/ExampleAdjunctionDiag2.fscg"
+        diagToPdf2 diag2 "OutputGraphViz/Examples/Adjunction/diag2"
+        catToPdf (mkConeCategory diag1) "OutputGraphViz/Examples/Adjunction/coneCat1"
+        catToPdf (mkConeCategory diag2) "OutputGraphViz/Examples/Adjunction/coneCat2"
+        putStrLn $ show $ (omap (limitFunctor (src diag1) (tgt diag1))) !-! diag1
+        putStrLn $ show $ (omap (limitFunctor (src diag2) (tgt diag2))) !-! diag2
+        putStrLn $ show $ (mmap (limitFunctor (src diag1) (tgt diag1))) !-! (head (ar FunctorCategory{sourceCat = src diag1, targetCat = tgt diag1} diag1 diag2))
+        putStrLn "End of ExampleAdjunction"
+        
+ test/ExampleAdjunction/ExampleAdjunction.scg view
@@ -0,0 +1,14 @@+6
+
+
+A -1-> B 
+B -5-> E
+A -2-> C
+C -6-> F
+D -3-> E
+D -4-> F
+A -7-> D
+
+
+A -7-> D -4-> F = A -2-> C -6-> F
+A -7-> D -3-> E = A -1-> B -5-> E
+ test/ExampleAdjunction/ExampleAdjunctionDiag1.fscg view
@@ -0,0 +1,21 @@+<SRC>
+6
+0
+1
+</SRC>
+
+<TGT>
+6
+A -1-> B 
+B -5-> E
+A -2-> C
+C -6-> F
+D -3-> E
+D -4-> F
+A -7-> D
+A -7-> D -4-> F = A -2-> C -6-> F
+A -7-> D -3-> E = A -1-> B -5-> E
+</TGT>
+
+0 => B
+1 => C
+ test/ExampleAdjunction/ExampleAdjunctionDiag2.fscg view
@@ -0,0 +1,21 @@+<SRC>
+6
+0
+1
+</SRC>
+
+<TGT>
+6
+A -1-> B 
+B -5-> E
+A -2-> C
+C -6-> F
+D -3-> E
+D -4-> F
+A -7-> D
+A -7-> D -4-> F = A -2-> C -6-> F
+A -7-> D -3-> E = A -1-> B -5-> E
+</TGT>
+
+0 => E
+1 => F
+ test/ExampleCat/ExampleCat.hs view
@@ -0,0 +1,41 @@+{-| Module  : FiniteCategories
+Description : An example of a category of categories.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of category of categories.
+-}
+module ExampleCat.ExampleCat
+(
+    set1, set2, cat,
+    main
+)
+where
+    import Prelude hiding (fmap, Functor)
+    import              Cat.FinCat                             (FinCat(..))
+    import              Set.FinOrdSet                             (FinOrdSet(..))
+    import              Data.Set                               (fromList)
+    import              ExportGraphViz.ExportGraphViz          (catToPdf,genToPdf)
+    import              Cat.FinCat
+    import              FiniteCategory.FiniteCategory
+
+    -- | A category with {1,2} and {3} as object and applications as morphisms.
+    set1 = FinOrdSet [fromList [1, 2], fromList [3]] :: FinOrdSet Int
+    -- | A category with {1,2} as object and applications as morphisms.
+    set2 = FinOrdSet [fromList [1,2]] :: FinOrdSet Int
+    
+    -- | A category with the two previous categories as objects
+    cat = FinCat [set1,set2]
+
+    -- | Export all the previously defined categories as pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleCat"
+        catToPdf set1 "OutputGraphViz/Examples/Cat/CatOfSet/set1"
+        catToPdf set2 "OutputGraphViz/Examples/Cat/CatOfSet/set2"
+        catToPdf cat "OutputGraphViz/Examples/Cat/CatOfSet/cat"
+        putStrLn "End of ExampleCat"
+    
+        
+ test/ExampleCat/ExampleFunctor.hs view
@@ -0,0 +1,41 @@+{-| Module  : FiniteCategories
+Description : An example of functor.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of functor.
+-}
+module ExampleCat.ExampleFunctor
+(
+    funct,
+    main
+)
+where
+    import              Cat.FinCat                                      (FinCat(..))
+    import              FiniteCategory.FiniteCategory
+    import              RandomCompositionGraph.RandomCompositionGraph
+    import              CompositionGraph.CompositionGraph
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz                   (catToPdf,genToPdf,diagToPdf,diagToPdf2)
+    import              Cat.FinCat
+    import              Diagram.Conversion
+
+    (rcg1,newGen) = (mkRandomCompositionGraph 5 10 5 (mkStdGen 8))
+    
+    cat = FinCat [rcg1]
+    
+    -- | An arbitrary functor from the random composition graph to itself.
+    funct = (arrows cat) !! 51
+
+    -- | Export the category of finCat containing a random composition graph as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleFunctor"
+        catToPdf rcg1 "OutputGraphViz/Examples/Cat/Functor/rcg1"
+        catToPdf cat "OutputGraphViz/Examples/Cat/Functor/catRCG"
+        diagToPdf (finFunctorToDiagram funct) "OutputGraphViz/Examples/Cat/Functor/functor"
+        diagToPdf2 (finFunctorToDiagram funct) "OutputGraphViz/Examples/Cat/Functor/diag"
+        putStrLn "End of ExampleFunctor"
+        
+ test/ExampleCat/ExamplePartialFinCat.hs view
@@ -0,0 +1,40 @@+{-| Module  : FiniteCategories
+Description : An example of a category of categories with partial functors.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of category of categories with partial functors.
+-}
+module ExampleCat.ExamplePartialFinCat
+(
+    set1, set2, cat,
+    main
+)
+where
+    import Prelude hiding (fmap, Functor)
+    import              Cat.PartialFinCat                      (PartialFinCat(..))
+    import              Set.FinOrdSet                          (FinOrdSet(..))
+    import              Data.Set                               (fromList)
+    import              ExportGraphViz.ExportGraphViz          (catToPdf,genToPdf)
+    import              FiniteCategory.FiniteCategory
+
+    -- | A category with {1,2} and {3} as object and applications as morphisms.
+    set1 = FinOrdSet [fromList [1]] :: FinOrdSet Int
+    -- | A category with {1,2} as object and applications as morphisms.
+    set2 = FinOrdSet [fromList [1,2]] :: FinOrdSet Int
+    
+    -- | A category with the two previous categories as objects
+    cat = PartialFinCat [set1,set2]
+
+    -- | Export all the previously defined categories as pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExamplePartialFinCat"
+        catToPdf set1 "OutputGraphViz/Examples/Cat/PartialFinCat/set1"
+        catToPdf set2 "OutputGraphViz/Examples/Cat/PartialFinCat/set2"
+        catToPdf cat "OutputGraphViz/Examples/Cat/PartialFinCat/catOfCat"
+        putStrLn "End of ExamplePartialFinCat"
+    
+        
+ test/ExampleCommaCategory/ExampleArrowCategory.hs view
@@ -0,0 +1,34 @@+{-| Module  : FiniteCategories
+Description : An example of arrow category.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of arrow category.
+-}
+module ExampleCommaCategory.ExampleArrowCategory
+(
+    arrowCategory,
+    main
+)
+where
+    import              RandomCompositionGraph.RandomCompositionGraph
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz                   (catToPdf,diagToPdf,diagToPdf2)
+    import              FiniteCategory.FiniteCategory
+    import              CommaCategory.CommaCategory
+
+    (rcg1,newGen) = (mkRandomCompositionGraph 5 10 3 (mkStdGen 8789))
+    
+    -- | The category of arrows of a random composition graph.
+    arrowCategory = mkArrowCategory rcg1
+
+    -- | Export the arrow category as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleArrowCategory"
+        catToPdf rcg1 "OutputGraphViz/Examples/CommaCategory/ArrowCategory/rcg"
+        catToPdf arrowCategory "OutputGraphViz/Examples/CommaCategory/ArrowCategory/arrow"
+        putStrLn "End of ExampleArrowCategory"
+        
+ test/ExampleCommaCategory/ExampleCosliceCategory.hs view
@@ -0,0 +1,37 @@+{-| Module  : FiniteCategories
+Description : An example of coslice category.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of coslice category.
+-}
+module ExampleCommaCategory.ExampleCosliceCategory
+(
+    cosliceCategory,
+    main
+)
+where
+    import              RandomCompositionGraph.RandomCompositionGraph
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz                   (catToPdf,diagToPdf,diagToPdf2)
+    import              Diagram.Diagram                                 (mkIdentityDiagram)
+    import              FiniteCategory.FiniteCategory
+    import              CommaCategory.CommaCategory
+    import              Utils.Sample
+    import              Data.Maybe
+
+    (rcg1,newGen) = (defaultMkRandomCompositionGraph (mkStdGen 834589))
+    
+    -- | The category of objects under a random one.
+    cosliceCategory = fromJust $ mkCosliceCategory rcg1 (fst (pickOne (ob rcg1) newGen))
+
+    -- | Export the coslice category as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleCosliceCategory"
+        catToPdf rcg1 "OutputGraphViz/Examples/CommaCategory/CosliceCategory/rcg"
+        catToPdf cosliceCategory "OutputGraphViz/Examples/CommaCategory/CosliceCategory/coslice"
+        putStrLn "End of ExampleCosliceCategory"
+        
+ test/ExampleCommaCategory/ExampleSliceCategory.hs view
@@ -0,0 +1,37 @@+{-| Module  : FiniteCategories
+Description : An example of slice category.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of slice category.
+-}
+module ExampleCommaCategory.ExampleSliceCategory
+(
+    sliceCategory,
+    main
+)
+where
+    import              RandomCompositionGraph.RandomCompositionGraph
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz                   (catToPdf,diagToPdf,diagToPdf2)
+    import              Diagram.Diagram                                 (mkIdentityDiagram)
+    import              FiniteCategory.FiniteCategory
+    import              CommaCategory.CommaCategory
+    import              Utils.Sample
+    import              Data.Maybe
+
+    (rcg1,newGen) = (defaultMkRandomCompositionGraph (mkStdGen 83456789))
+    
+    -- | The category of objects over a random one.
+    sliceCategory = fromJust $ mkSliceCategory rcg1 (fst (pickOne (ob rcg1) newGen))
+
+    -- | Export the slice category as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleSliceCategory"
+        catToPdf rcg1 "OutputGraphViz/Examples/CommaCategory/SliceCategory/rcg"
+        catToPdf sliceCategory "OutputGraphViz/Examples/CommaCategory/SliceCategory/slice"
+        putStrLn "End of ExampleSliceCategory"
+        
+ test/ExampleCompositionGraph/ExampleCompositionGraph.hs view
@@ -0,0 +1,44 @@+{-| Module  : FiniteCategories
+Description : An example of composition graph.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of composition graph.
+-}
+module ExampleCompositionGraph.ExampleCompositionGraph
+(
+    square, main
+)
+where
+    import              CompositionGraph.CompositionGraph
+    import              ExportGraphViz.ExportGraphViz           (catToPdf)
+    import qualified    FiniteCategory.FiniteCategory as FinCat (FiniteCategoryError(..))
+    import              Data.Text                               (Text, pack)
+
+    f = (0, 1, pack "f") :: Arrow Int Text
+    g = (1, 2, pack "g") :: Arrow Int Text
+    h = (0, 3, pack "h") :: Arrow Int Text
+    i = (3, 2, pack "i") :: Arrow Int Text
+    
+    -- | A composition law defined by hand. 
+    myLaw = [([g,f],[i,h])]
+            
+    myGraph = ([0, 1, 2, 3], [f,g,h,i])
+    -- | An example of a composition graph
+    Right square = mkCompositionGraph myGraph myLaw
+    
+    my_sub_graph = ([0, 1, 3], [f,g,h,i])
+    -- | A composition subgraph of the previous composition graph.
+    csg = mkCompositionGraph my_sub_graph myLaw
+            
+    -- | Exports the composition graphs as pdf files with GraphViz.
+    main = main_ square csg where
+        main_ _ (Left err) = putStrLn.show $ err
+        main_ square (Right csg) = do
+            putStrLn "Start of ExampleCompositionGraph"
+            catToPdf square "OutputGraphViz/Examples/CompositionGraph/CompositionGraph/compositionGraph"
+            catToPdf csg "OutputGraphViz/Examples/CompositionGraph/CompositionGraph/compositionGraph2"
+            putStrLn "End of ExampleCompositionGraph"
+ test/ExampleCompositionGraph/ExampleCompositionGraphConstruction.hs view
@@ -0,0 +1,80 @@+{-| Module  : FiniteCategories
+Description : An example of `CompositionGraph` construction with insertion, modification and deletion.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of `CompositionGraph` construction with insertion, modification and deletion.
+-}
+module ExampleCompositionGraph.ExampleCompositionGraphConstruction
+(
+    main
+)
+where
+    import              CompositionGraph.CompositionGraph
+    import              ExportGraphViz.ExportGraphViz
+    import              Diagram.Diagram
+    import              FiniteCategory.FiniteCategory
+    import              Data.Text                               (Text, pack)
+    import              Data.List                               ((\\))
+    import              Diagram.Conversion
+    
+    cg1 = mkEmptyCompositionGraph :: CompositionGraph Text Text
+    (cg2,funct2) = insertObject cg1 (pack "1")
+    (cg3,funct3) = insertObject cg2 (pack "2")
+    Right (cg4,funct4) = insertMorphism cg3 ((pack "1")) ((pack "2")) (pack "f")
+    Right (cg5,funct5) = insertMorphism cg4 ((pack "1")) ((pack "1")) (pack "g")
+    Right (cg6,funct6) = identifyMorphisms cg5 ((head [f | f <- genAr cg5 ((pack "1")) ((pack "1")), isNotIdentity cg5 f]) @ (head [f | f <- genAr cg5 ((pack "1")) ((pack "1")), isNotIdentity cg5 f])) (head [f | f <- genAr cg5 ((pack "1")) ((pack "1")), isNotIdentity cg5 f])
+    Right (cg7,funct7) = replaceObject cg6 (pack "2") (pack "3")
+    Right (cg8,funct8) = replaceMorphism cg7 (head (ar cg7 (pack "1") (pack "3"))) (pack "h")
+    (cg9,funct9) = insertObject cg8 (pack "4")
+    Right (cg10,funct10) = insertMorphism cg9 ((pack "3")) ((pack "4")) (pack "i")
+    Right (cg11,funct11) = insertMorphism cg10 ((pack "1")) ((pack "4")) (pack "j")
+    Right (cg12,funct12) = identifyMorphisms cg11 (((ar cg11 (pack "1") (pack "4")) \\ (genAr cg11 (pack "1") (pack "4")))!!1) (head (genAr cg11 (pack "1") (pack "4")))
+    Right (cg13,funct13) = deleteMorphism cg12 (head (genAr cg12 (pack "1") (pack "4")))
+    Right (cg14,funct14) = deleteObject cg13 (pack "4")
+    Right (cg15,funct15) = identifyMorphisms cg14 ((ar cg14 (pack "1") (pack "3"))!!1) ((ar cg14 (pack "1") (pack "3"))!!0)
+    Right (cg16,funct16) = unidentifyMorphism cg15 ((ar cg15 (pack "1") (pack "3"))!!0)
+            
+    Just diag2 = partialFunctorToDiagram funct2
+    Just diag3 = partialFunctorToDiagram funct3
+    Just diag4 = partialFunctorToDiagram funct4
+    -- we don't create diag5 and diag6 because their are not showable as categories are infinite.
+    Just diag7 = partialFunctorToDiagram funct7
+    Just diag8 = partialFunctorToDiagram funct8
+    Just diag9 = partialFunctorToDiagram funct9
+    Just diag10 = partialFunctorToDiagram funct10
+    Just diag11 = partialFunctorToDiagram funct11
+    -- we don't create diag12, diag13, diag14 and diag15 because they are not total.
+    Just diag16 = partialFunctorToDiagram funct16
+            
+    -- | Exports the composition graphs and insertion functors as pdf file with GraphViz.
+    main = do
+            putStrLn "Start of ExampleCompositionGraphConstruction"
+            catToPdf cg1 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/cat1"
+            catToPdf cg2 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/cat2"
+            catToPdf cg3 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/cat3"
+            catToPdf cg4 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/cat4"
+            catToPdf cg6 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/cat6"
+            catToPdf cg7 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/cat7"
+            catToPdf cg8 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/cat8"
+            catToPdf cg9 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/cat9"
+            catToPdf cg10 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/cat10"
+            catToPdf cg11 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/cat11"
+            catToPdf cg12 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/cat12"
+            catToPdf cg13 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/cat13"
+            catToPdf cg14 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/cat14"
+            catToPdf cg15 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/cat15"
+            catToPdf cg16 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/cat16"
+            diagToPdf diag2 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/funct2"
+            diagToPdf diag3 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/funct3"
+            diagToPdf diag4 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/funct4"
+            diagToPdf diag7 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/funct7"
+            diagToPdf diag8 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/funct8"
+            diagToPdf diag9 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/funct9"
+            diagToPdf diag10 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/funct10"
+            diagToPdf diag11 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/funct11"
+            diagToPdf diag16 "OutputGraphViz/Examples/CompositionGraph/CompositionGraphConstruction/funct16"
+            putStrLn "End of ExampleCompositionGraphConstruction"
+ test/ExampleCompositionGraph/ExampleFinSetToCompositionGraph.hs view
@@ -0,0 +1,34 @@+{-| Module  : FiniteCategories
+Description : An example of conversion from a `FinOrdSet` category to a `CompositionGraph`.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of conversion from a `FinOrdSet` category to a `CompositionGraph`.
+-}
+module ExampleCompositionGraph.ExampleFinSetToCompositionGraph
+(
+    main
+)
+where
+    import              CompositionGraph.CompositionGraph
+    import              Set.FinOrdSet
+    import              Data.Set                                (fromList)
+    import              ExportGraphViz.ExportGraphViz
+    import qualified    FiniteCategory.FiniteCategory as FinCat (FiniteCategoryError(..))
+    import              Data.Text                               (Text, pack)
+
+    finSet = FinOrdSet [fromList [1,2], fromList [3]] :: FinOrdSet Int
+    
+    (cg, iso) = generatedFiniteCategoryToCompositionGraph finSet
+            
+    -- | Exports the composition graph as pdf file with GraphViz.
+    main = do
+            putStrLn "Start of ExampleFinSetToCompositionGraph"
+            catToPdf finSet "OutputGraphViz/Examples/CompositionGraph/FinSetToCompositionGraph/finSet"
+            catToPdf cg "OutputGraphViz/Examples/CompositionGraph/FinSetToCompositionGraph/compositionGraph"
+            diagToPdf iso "OutputGraphViz/Examples/CompositionGraph/FinSetToCompositionGraph/funct"
+            diagToPdf2 iso "OutputGraphViz/Examples/CompositionGraph/FinSetToCompositionGraph/diag"
+            putStrLn "End of ExampleFinSetToCompositionGraph"
+ test/ExampleCompositionGraph/ExampleSafeCompositionGraph.hs view
@@ -0,0 +1,47 @@+{-| Module  : FiniteCategories
+Description : An example of safe composition graph.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of safe composition graph.
+-}
+module ExampleCompositionGraph.ExampleSafeCompositionGraph
+(
+    squareS, main
+)
+where
+    import              CompositionGraph.CompositionGraph
+    import              CompositionGraph.SafeCompositionGraph
+    import              ExportGraphViz.ExportGraphViz           (catToPdf)
+    import qualified    FiniteCategory.FiniteCategory as FinCat (FiniteCategoryError(..))
+    import              Data.Text                               (Text, pack)
+
+    f = (0, 1, pack "f") :: Arrow Int Text
+    g = (1, 2, pack "g") :: Arrow Int Text
+    h = (0, 3, pack "h") :: Arrow Int Text
+    i = (3, 2, pack "i") :: Arrow Int Text
+    j = (3, 3, pack "j") :: Arrow Int Text
+    
+    -- | A composition law defined by hand. 
+    myLaw = [([g,f],[i,h])]
+            
+    myGraph = ([0, 1, 2, 3], [f,g,h,i,j])
+    -- | An example of a composition graph
+    squareS = mkSafeCompositionGraph myGraph myLaw 3
+    
+    my_sub_graph = ([0, 1, 2], [f,j])
+    -- | A composition subgraph of the previous composition graph.
+    csg = mkSafeCompositionGraph my_sub_graph myLaw 2
+            
+    -- | Exports the composition graphs as pdf files with GraphViz.
+    main = main_ squareS csg where
+        main_ (Left err) _ = putStrLn.show $ err
+        main_ _ (Left err) = putStrLn.show $ err
+        main_ (Right squareS) (Right csg) = do
+            putStrLn "Start of ExampleSafeCompositionGraph"
+            catToPdf squareS "OutputGraphViz/Examples/CompositionGraph/SafeCompositionGraph/compositionGraph"
+            catToPdf csg "OutputGraphViz/Examples/CompositionGraph/SafeCompositionGraph/compositionGraph2"
+            putStrLn "End of ExampleSafeCompositionGraph"
+ test/ExampleConeCategory/ExampleCoconeCategory.hs view
@@ -0,0 +1,44 @@+{-| Module  : FiniteCategories
+Description : An example of cocone category.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of cocone category.
+-}
+module ExampleConeCategory.ExampleCoconeCategory
+(
+    main
+)
+where
+    import              RandomCompositionGraph.RandomCompositionGraph
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz
+    import              FiniteCategory.FiniteCategory
+    import              FunctorCategory.FunctorCategory
+    import              Diagram.Diagram
+    import              UsualCategories.Three
+    import              Utils.Sample
+    import              Data.Maybe
+    import              ConeCategory.ConeCategory
+    import              IO.PrettyPrint
+
+    (rcg,newGen) = (mkRandomCompositionGraph 20 25 5 (mkStdGen 878))
+    
+    (diag,newGen1) = (pickOne (ob FunctorCategory{sourceCat=Three, targetCat=rcg}) newGen)
+    
+    coconeCategory = mkCoconeCategory diag
+
+    -- | Export the cocone category as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleCoconeCategory"
+        catToPdf rcg "OutputGraphViz/Examples/ConeCategory/Cocone/rcg"
+        diagToPdf diag "OutputGraphViz/Examples/ConeCategory/Cocone/funct"
+        diagToPdf2 diag "OutputGraphViz/Examples/ConeCategory/Cocone/diag"
+        catToPdf coconeCategory "OutputGraphViz/Examples/ConeCategory/Cocone/coconeCategory"
+        putStrLn "Colimits : "
+        putStrLn $ pprint $ initialObjects coconeCategory
+        putStrLn "End of ExampleCoconeCategory"
+        
+ test/ExampleConeCategory/ExampleColimit.hs view
@@ -0,0 +1,46 @@+{-| Module  : FiniteCategories
+Description : An example of colimits of a diagram.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of colimits of a diagram.
+-}
+module ExampleConeCategory.ExampleColimit
+(
+    main
+)
+where
+    import              RandomCompositionGraph.RandomCompositionGraph
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz
+    import              FiniteCategory.FiniteCategory
+    import              FunctorCategory.FunctorCategory
+    import              Diagram.Diagram
+    import              UsualCategories.Three
+    import              Utils.Sample
+    import              ConeCategory.ConeCategory
+
+    (rcg,newGen) = (mkRandomCompositionGraph 20 25 5 (mkStdGen 878))
+    
+    (diag,newGen1) = (pickOne (ob FunctorCategory{sourceCat=Three, targetCat=rcg}) newGen)
+    
+    colimit = colimits diag
+    
+    recuNatToPdf [] = putStrLn "End of natural transformation export"
+    recuNatToPdf (x:xs) = do
+                            natToPdf (coconeToNaturalTransformation x) ("OutputGraphViz/Examples/ConeCategory/Colimit/nat"++show (length xs))
+                            putStrLn $ show $ (naturalTransformationToCocone (coconeToNaturalTransformation x)) == x
+                            recuNatToPdf xs
+
+    -- | Export the colimits as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleColimit"
+        catToPdf rcg "OutputGraphViz/Examples/ConeCategory/Colimit/rcg"
+        diagToPdf diag "OutputGraphViz/Examples/ConeCategory/Colimit/funct"
+        diagToPdf2 diag "OutputGraphViz/Examples/ConeCategory/Colimit/diag"
+        recuNatToPdf colimit
+        putStrLn "End of ExampleColimit"
+        
+ test/ExampleConeCategory/ExampleConeCategory.hs view
@@ -0,0 +1,42 @@+{-| Module  : FiniteCategories
+Description : An example of cone category.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of cone category.
+-}
+module ExampleConeCategory.ExampleConeCategory
+(
+    main
+)
+where
+    import              RandomCompositionGraph.RandomCompositionGraph
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz
+    import              FiniteCategory.FiniteCategory
+    import              FunctorCategory.FunctorCategory
+    import              Diagram.Diagram
+    import              UsualCategories.Three
+    import              Utils.Sample
+    import              Data.Maybe
+    import              ConeCategory.ConeCategory
+    import              CommaCategory.CommaCategory
+    import              IO.PrettyPrint
+    import              RandomDiagram.RandomDiagram
+    import              IO.Parsers.SafeCompositionGraphFunctor
+
+    -- | Export the cone category as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleConeCategory"
+        diag <- readFSCGFile "test/ExampleConeCategory/diagram.fscg"
+        let coneCategory = mkConeCategory diag
+        catToPdf (tgt diag) "OutputGraphViz/Examples/ConeCategory/Cone/category"
+        diagToPdf diag "OutputGraphViz/Examples/ConeCategory/Cone/funct"
+        diagToPdf2 diag "OutputGraphViz/Examples/ConeCategory/Cone/diag"
+        catToPdf coneCategory "OutputGraphViz/Examples/ConeCategory/Cone/coneCategory"
+        sequence $ (\(x,y) -> natToPdf (arrow x) ("OutputGraphViz/Examples/ConeCategory/Cone/cone"++(show y))) <$> (zip (ob coneCategory) [1..]) 
+        putStrLn "End of ExampleConeCategory"
+        
+ test/ExampleConeCategory/ExampleLeftCone.hs view
@@ -0,0 +1,40 @@+{-| Module  : FiniteCategories
+Description : An example of cone category.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of cone category.
+-}
+module ExampleConeCategory.ExampleLeftCone
+(
+    main
+)
+where
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz
+    import              ConeCategory.LeftCone
+    import              Diagram.Diagram
+    import              FiniteCategory.FiniteCategory
+    import              IO.Parsers.SafeCompositionGraphFunctor
+
+    -- | Export the cone category as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleLeftCone"
+        diag <- readFSCGFile "test/ExampleConeCategory/diagram.fscg"
+        let leftCone = LeftCone (src diag)
+        let inclusionLeftCone = inclusionFunctor leftCone
+        let coneCat = ConeCategory diag
+        catToPdf (src diag) "OutputGraphViz/Examples/ConeCategory/LeftCone/I"
+        catToPdf leftCone "OutputGraphViz/Examples/ConeCategory/LeftCone/leftCone"
+        diagToPdf inclusionLeftCone "OutputGraphViz/Examples/ConeCategory/LeftCone/inclusionFunctor"
+        diagToPdf2 inclusionLeftCone "OutputGraphViz/Examples/ConeCategory/LeftCone/inclusionDiagram"
+        diagToPdf diag "OutputGraphViz/Examples/ConeCategory/LeftCone/diagAsFunct"
+        diagToPdf2 diag "OutputGraphViz/Examples/ConeCategory/LeftCone/diag"
+        catToPdf coneCat "OutputGraphViz/Examples/ConeCategory/LeftCone/coneCategory"
+        diagToPdf ((ob coneCat) !! 0) "OutputGraphViz/Examples/ConeCategory/LeftCone/exampleOfCone"
+        diagToPdf2 ((ob coneCat) !! 0) "OutputGraphViz/Examples/ConeCategory/LeftCone/exampleOfConeAsDiag"
+        putStrLn "End of ExampleLeftCone"
+        
+ test/ExampleConeCategory/ExampleLimit.hs view
@@ -0,0 +1,45 @@+{-| Module  : FiniteCategories
+Description : An example of limits of a diagram.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of limits of a diagram.
+-}
+module ExampleConeCategory.ExampleLimit
+(
+    main
+)
+where
+    import              RandomCompositionGraph.RandomCompositionGraph
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz
+    import              FiniteCategory.FiniteCategory
+    import              FunctorCategory.FunctorCategory
+    import              Diagram.Diagram
+    import              UsualCategories.Three
+    import              Utils.Sample
+    import              ConeCategory.ConeCategory
+
+    (rcg,newGen) = (mkRandomCompositionGraph 20 25 5 (mkStdGen 878))
+    
+    (diag,newGen1) = (pickOne (ob FunctorCategory{sourceCat=Three, targetCat=rcg}) newGen)
+    
+    limit = limits diag
+    
+    recuNatToPdf [] = putStrLn "End of natural transformation export"
+    recuNatToPdf (x:xs) = do
+                            natToPdf (coneToNaturalTransformation x) ("OutputGraphViz/Examples/ConeCategory/Limit/nat"++show (length xs))
+                            recuNatToPdf xs
+
+    -- | Export the limits as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleLimit"
+        catToPdf rcg "OutputGraphViz/Examples/ConeCategory/Limit/rcg"
+        diagToPdf diag "OutputGraphViz/Examples/ConeCategory/Limit/funct"
+        diagToPdf2 diag "OutputGraphViz/Examples/ConeCategory/Limit/diag"
+        recuNatToPdf limit
+        putStrLn "End of ExampleLimit"
+        
+ test/ExampleCurrying/ExampleCurrying.hs view
@@ -0,0 +1,43 @@+{-| Module  : FiniteCategories
+Description : An example of currying a functor.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of currying a functor.
+-}
+module ExampleCurrying.ExampleCurrying
+(
+    main
+)
+where
+    import              ExportGraphViz.ExportGraphViz          (catToPdf,genToPdf, diagToPdf2)
+    import              FiniteCategory.FiniteCategory
+    import              UsualCategories.Square
+    import              YonedaEmbedding.YonedaEmbedding
+    import              Diagram.Diagram
+    import              Subcategories.Subcategory
+    import              Currying.Currying
+    
+    -- | We select A and D in the Square category.
+    Just diag = mkDiscreteDiagram Square [A,D]
+    -- Just diag = mkSelect2 Square FH
+    
+    -- | We Yoneda embed the Square category.
+    (yoneda,embedding) = yonedaEmbedding Square
+
+    -- | We compose diag and embedding.
+    curriedDiag = composeDiag embedding diag
+
+    -- | Export all the previously defined categories as pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleCurrying"
+        diagToPdf2 (fullDiagram curriedDiag) "OutputGraphViz/Examples/ExampleCurrying/yonedaEmbedding"
+        diagToPdf2 (fullDiagram (uncurryDiagram curriedDiag)) "OutputGraphViz/Examples/ExampleCurrying/uncurriedYonedaEmbedding"
+        diagToPdf2 (fullDiagram (curryDiagram (uncurryDiagram curriedDiag))) "OutputGraphViz/Examples/ExampleCurrying/curriedUncurriedYonedaEmbedding"
+        diagToPdf2 (fullDiagram (switchArg curriedDiag)) "OutputGraphViz/Examples/ExampleCurrying/switchArgYoneda"
+        putStrLn "End of ExampleCurrying"
+    
+        
+ test/ExampleDiagonalFunctor/ExampleDiagonalFunctor.hs view
@@ -0,0 +1,51 @@+{-| Module  : FiniteCategories
+Description : An example of diagonal functor.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of diagonal functor.
+-}
+module ExampleDiagonalFunctor.ExampleDiagonalFunctor
+(
+    diagonalFunctor,
+    main
+)
+where
+    import              RandomCompositionGraph.RandomCompositionGraph
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz
+    import              FiniteCategory.FiniteCategory
+    import              Diagram.Diagram
+    import              UsualCategories.Three
+    import              UsualCategories.Two
+    import              DiagonalFunctor.DiagonalFunctor
+    import              FunctorCategory.FunctorCategory
+    import              CompositionGraph.CompositionGraph
+
+    (rcg1,newGen) = (mkRandomCompositionGraph 6 10 4 (mkStdGen 10987654))
+    
+    -- | A diagonal functor.
+    diagonalFunctor = mkDiagonalFunctor Two rcg1
+    
+    recuNatToPdf [] = putStrLn "End of natural transformation export"
+    recuNatToPdf (x:xs) = do
+                            natToPdf x ("OutputGraphViz/Examples/DiagonalFunctor/nat"++show (length xs))
+                            recuNatToPdf xs
+    
+    recuDiagToPdf [] = putStrLn "End of diagrams export"
+    recuDiagToPdf (x:xs) = do
+                            diagToPdf2 x ("OutputGraphViz/Examples/DiagonalFunctor/diag"++show (length xs))
+                            recuDiagToPdf xs
+
+    -- | Export the diagonal functor as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleDiagonalFunctor"
+        catToPdf rcg1 "OutputGraphViz/Examples/DiagonalFunctor/rcg1"
+        recuDiagToPdf (ob.tgt $ diagonalFunctor)
+        recuNatToPdf (arrows.tgt $ diagonalFunctor)
+        diagToPdf2 diagonalFunctor "OutputGraphViz/Examples/DiagonalFunctor/diagonalFunctor"
+        putStrLn "End of ExampleDiagonalFunctor"
+        
+ test/ExampleDiagram/ExampleConstantDiagram.hs view
@@ -0,0 +1,40 @@+{-| Module  : FiniteCategories
+Description : An example of constant diagram.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of constant diagram.
+-}
+module ExampleDiagram.ExampleConstantDiagram
+(
+    constantDiag,
+    main
+)
+where
+    import              RandomCompositionGraph.RandomCompositionGraph
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz                   (catToPdf,diagToPdf,diagToPdf2)
+    import              Diagram.Diagram                                 (mkConstantDiagram)
+    import              CompositionGraph.CompositionGraph
+    import              Utils.Sample
+    import              FiniteCategory.FiniteCategory
+    import              Data.Maybe                                      (fromJust)
+
+    (rcg1,newGen) = (defaultMkRandomCompositionGraph (mkStdGen 8))
+    (rcg2,newGen1) = (defaultMkRandomCompositionGraph newGen)
+    
+    -- | The constant diagram from a random composition graph to a random object.
+    constantDiag = fromJust $ mkConstantDiagram rcg1 rcg2 (fst (pickOne (ob rcg2) newGen1))
+
+    -- | Export the constant diagram as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleConstantDiagram"
+        catToPdf rcg1 "OutputGraphViz/Examples/Diagram/ConstantDiagram/rcg1"
+        catToPdf rcg2 "OutputGraphViz/Examples/Diagram/ConstantDiagram/rcg2"
+        diagToPdf constantDiag "OutputGraphViz/Examples/Diagram/ConstantDiagram/functor"
+        diagToPdf2 constantDiag "OutputGraphViz/Examples/Diagram/ConstantDiagram/diag"
+        putStrLn "End of ExampleConstantDiagram"
+        
+ test/ExampleDiagram/ExampleConversion.hs view
@@ -0,0 +1,36 @@+{-| Module  : FiniteCategories
+Description : Examples of functor conversion.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Examples of functor conversion.
+-}
+module ExampleDiagram.ExampleConversion
+(
+    main
+)
+where
+    import              RandomDiagram.RandomDiagram
+    import              Diagram.Conversion
+    import              ExportGraphViz.ExportGraphViz
+    import              System.Random
+    import              Data.Maybe
+
+    (diag,newGen) = (defaultMkRandomDiagram (mkStdGen 745678))
+    finFunct = diagramToFinFunctor diag
+    partialFunct = diagramToPartialFunctor diag
+    Just finFunct2 = partialFunctorToFinFunctor partialFunct
+    partialFunct2 = finFunctorToPartialFunctor finFunct
+
+    -- | Export the diagram as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleConversion"
+        diagToPdf diag "OutputGraphViz/Examples/Diagram/Conversion/diag"
+        diagToPdf (finFunctorToDiagram finFunct) "OutputGraphViz/Examples/Diagram/Conversion/finFunct"
+        diagToPdf (fromJust $ partialFunctorToDiagram partialFunct) "OutputGraphViz/Examples/Diagram/Conversion/partialFunct"
+        diagToPdf (finFunctorToDiagram finFunct2) "OutputGraphViz/Examples/Diagram/Conversion/finFunct2"
+        diagToPdf (fromJust $ partialFunctorToDiagram partialFunct2) "OutputGraphViz/Examples/Diagram/Conversion/partialFunct2"
+        putStrLn "End of ExampleConversion"
+ test/ExampleDiagram/ExampleDiagram.hs view
@@ -0,0 +1,53 @@+{-| Module  : FiniteCategories
+Description : An example of an arbitray diagram.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of an arbitray diagram. We select a square in a random composition graph.
+-}
+module ExampleDiagram.ExampleDiagram
+(
+    diag,
+    main
+)
+where
+    import              RandomCompositionGraph.RandomCompositionGraph
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz                   (catToPdf,diagToPdf,diagToPdf2)
+    import              Diagram.Diagram                                 (mkDiagram, src, completeMmap)
+    import              CompositionGraph.CompositionGraph
+    import              Utils.Sample
+    import              FiniteCategory.FiniteCategory            hiding (FiniteCategoryError(..))
+    import              Data.Maybe                                      (fromJust)
+    import              Data.Map                                        (Map, fromList)
+    import              ExampleCompositionGraph.ExampleCompositionGraph (square)
+    import              Utils.AssociationList
+
+    (rcg1,newGen) = (mkRandomCompositionGraph 20 25 3 (mkStdGen 12345))
+    
+    -- | We select a square in the random category.
+    diag = fromJust $ mkDiagram square rcg1 (functToAssocList om (ob square)) fm
+        where
+            om 0 = 30
+            om 1 = 20
+            om 2 = 31
+            om 3 = 29
+            fm = completeMmap square rcg1 (functToAssocList om (ob square)) (functToAssocList fm_ (arrows square))
+                where
+                    fm_ x
+                        | x == (head (genAr square 0 1)) = head $ genAr rcg1 30 20
+                        | x == (head (genAr square 1 2)) = head $ genAr rcg1 20 31
+                        | x == (head (genAr square 0 3)) = head $ genAr rcg1 30 29
+                        | x == (head (genAr square 3 2)) = head $ genAr rcg1 29 31
+
+    -- | Export the diagram as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleDiagram"
+        catToPdf rcg1 "OutputGraphViz/Examples/Diagram/Diagram/rcg1"
+        catToPdf square "OutputGraphViz/Examples/Diagram/Diagram/square"
+        diagToPdf diag "OutputGraphViz/Examples/Diagram/Diagram/functor"
+        diagToPdf2 diag "OutputGraphViz/Examples/Diagram/Diagram/diag"
+        putStrLn "End of ExampleDiagram"
+ test/ExampleDiagram/ExampleDiscreteDiagram.hs view
@@ -0,0 +1,37 @@+{-| Module  : FiniteCategories
+Description : An example of discrete diagram.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of discrete diagram.
+-}
+module ExampleDiagram.ExampleDiscreteDiagram
+(
+    discreteDiag,
+    main
+)
+where
+    import              RandomCompositionGraph.RandomCompositionGraph
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz                   (catToPdf,diagToPdf,diagToPdf2)
+    import              Diagram.Diagram                                 (mkDiscreteDiagram)
+    import              CompositionGraph.CompositionGraph
+    import              Utils.Sample
+    import              FiniteCategory.FiniteCategory
+    import              Data.Maybe                                      (fromJust)
+
+    (rcg1,newGen) = (mkRandomCompositionGraph 10 10 3 (mkStdGen 567))
+    
+    -- | The discrete diagram to a random composition graph where we select a few random objects.
+    discreteDiag = fromJust $ mkDiscreteDiagram rcg1 (fst (sample (ob rcg1) 4 newGen))
+
+    -- | Export the discrete diagram as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleDiscreteDiagram"
+        catToPdf rcg1 "OutputGraphViz/Examples/Diagram/DiscreteDiagram/rcg1"
+        diagToPdf discreteDiag "OutputGraphViz/Examples/Diagram/DiscreteDiagram/functor"
+        diagToPdf2 discreteDiag "OutputGraphViz/Examples/Diagram/DiscreteDiagram/diag"
+        putStrLn "End of ExampleDiscreteDiagram"
+ test/ExampleDiagram/ExampleIdentityDiagram.hs view
@@ -0,0 +1,35 @@+{-| Module  : FiniteCategories
+Description : An example of identity diagram.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of identity diagram.
+-}
+module ExampleDiagram.ExampleIdentityDiagram
+(
+    identityDiag,
+    main
+)
+where
+    import              RandomCompositionGraph.RandomCompositionGraph
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz                   (catToPdf,diagToPdf,diagToPdf2)
+    import              Diagram.Diagram                                 (mkIdentityDiagram)
+    import              FiniteCategory.FiniteCategory
+
+    (rcg1,newGen) = (defaultMkRandomCompositionGraph (mkStdGen 83456789))
+    
+    -- | The identity diagram on a random composition graph.
+    identityDiag = mkIdentityDiagram rcg1
+
+    -- | Export the constant diagram as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleIdentityDiagram"
+        catToPdf rcg1 "OutputGraphViz/Examples/Diagram/IdentityDiagram/rcg1"
+        diagToPdf identityDiag "OutputGraphViz/Examples/Diagram/IdentityDiagram/functor"
+        diagToPdf2 identityDiag "OutputGraphViz/Examples/Diagram/IdentityDiagram/diag"
+        putStrLn "End of ExampleIdentityDiagram"
+        
+ test/ExampleDiagram/ExampleParallelDiagram.hs view
@@ -0,0 +1,40 @@+{-| Module  : FiniteCategories
+Description : An example of parallel diagram.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of parallel diagram.
+-}
+module ExampleDiagram.ExampleParallelDiagram
+(
+    parallelDiag,
+    main
+)
+where
+    import              RandomCompositionGraph.RandomCompositionGraph
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz                   (catToPdf,diagToPdf,diagToPdf2)
+    import              Diagram.Diagram                                 (mkParallel, src)
+    import              Utils.Sample
+    import              FiniteCategory.FiniteCategory       hiding      (FiniteCategoryError(..))
+    import              Data.Maybe                                      (fromJust)
+
+    (rcg1,newGen) = (mkRandomCompositionGraph 10 15 3 (mkStdGen 1234))
+    
+    (arToPickFrom,newGen2) = (pickOne [ar rcg1 a b|a <- ob rcg1, b <- ob rcg1, length (ar rcg1 a b) > 1, a/=b] newGen)
+    ([f,g],newGen3) = (sample arToPickFrom 2 newGen2)
+    
+    -- | We select a two parallel morphism in a random category.
+    parallelDiag = fromJust $ (mkParallel rcg1 f g)
+
+    -- | Export the diagram as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleParallelDiagram"
+        catToPdf rcg1 "OutputGraphViz/Examples/Diagram/ParallelDiagram/rcg1"
+        catToPdf (src parallelDiag) "OutputGraphViz/Examples/Diagram/ParallelDiagram/Parallel"
+        diagToPdf parallelDiag "OutputGraphViz/Examples/Diagram/ParallelDiagram/functor"
+        diagToPdf2 parallelDiag "OutputGraphViz/Examples/Diagram/ParallelDiagram/diag"
+        putStrLn "End of ExampleParallelDiagram"
+ test/ExampleDiagram/ExampleSelectOneDiagram.hs view
@@ -0,0 +1,39 @@+{-| Module  : FiniteCategories
+Description : An example of select1 diagram.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of select1 diagram.
+-}
+module ExampleDiagram.ExampleSelectOneDiagram
+(
+    selectOne,
+    main
+)
+where
+    import              RandomCompositionGraph.RandomCompositionGraph
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz                   (catToPdf,diagToPdf,diagToPdf2)
+    import              Diagram.Diagram                                 (mkSelect1, src)
+    import              Utils.Sample
+    import              FiniteCategory.FiniteCategory
+    import              Data.Maybe                                      (fromJust)
+
+    (rcg1,newGen) = (mkRandomCompositionGraph 10 10 3 (mkStdGen 567678))
+    
+    -- | We select one object in a random category.
+    selectOne = fromJust $ mkSelect1 rcg1 (fst (pickOne (ob rcg1) newGen))
+
+    -- | Export the diagram as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleSelectOneDiagram"
+        catToPdf rcg1 "OutputGraphViz/Examples/Diagram/SelectOneDiagram/rcg1"
+        catToPdf (src selectOne) "OutputGraphViz/Examples/Diagram/SelectOneDiagram/One"
+        diagToPdf selectOne "OutputGraphViz/Examples/Diagram/SelectOneDiagram/functor"
+        diagToPdf2 selectOne "OutputGraphViz/Examples/Diagram/SelectOneDiagram/diag"
+        putStrLn "End of ExampleSelectOneDiagram"
+        
+        
+ test/ExampleDiagram/ExampleSelectThreeDiagram.hs view
@@ -0,0 +1,41 @@+{-| Module  : FiniteCategories
+Description : An example of select3 diagram.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of select3 diagram.
+-}
+module ExampleDiagram.ExampleSelectThreeDiagram
+(
+    selectThree,
+    main
+)
+where
+    import              RandomCompositionGraph.RandomCompositionGraph
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz                   (catToPdf,diagToPdf,diagToPdf2)
+    import              Diagram.Diagram                                 (mkSelect3, src)
+    import              Utils.Sample
+    import              FiniteCategory.FiniteCategory            hiding (FiniteCategoryError(..))
+    import              Data.List                                       ((\\))
+    import              Data.Maybe                                      (fromJust)
+
+    (rcg1,newGen) = (mkRandomCompositionGraph 10 15 3 (mkStdGen 1234))
+    
+    (f,newGen2) = (pickOne ((arrows rcg1)\\(identities rcg1)) newGen)
+    (g,newGen3) = (pickOne ((arFrom rcg1 (target f))) newGen2)
+    
+    -- | We select a triangle in a random category.
+    selectThree = fromJust $ (mkSelect3 rcg1 f g)
+
+    -- | Export the diagram as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleSelectThreeDiagram"
+        catToPdf rcg1 "OutputGraphViz/Examples/Diagram/SelectThreeDiagram/rcg1"
+        catToPdf (src selectThree) "OutputGraphViz/Examples/Diagram/SelectThreeDiagram/Three"
+        diagToPdf selectThree "OutputGraphViz/Examples/Diagram/SelectThreeDiagram/functor"
+        diagToPdf2 selectThree "OutputGraphViz/Examples/Diagram/SelectThreeDiagram/diag"
+        putStrLn "End of ExampleSelectThreeDiagram"
+ test/ExampleDiagram/ExampleSelectTwoDiagram.hs view
@@ -0,0 +1,38 @@+{-| Module  : FiniteCategories
+Description : An example of select2 diagram.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of select2 diagram.
+-}
+module ExampleDiagram.ExampleSelectTwoDiagram
+(
+    selectTwo,
+    main
+)
+where
+    import              RandomCompositionGraph.RandomCompositionGraph
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz                   (catToPdf,diagToPdf,diagToPdf2)
+    import              Diagram.Diagram                                 (mkSelect2, src)
+    import              Utils.Sample
+    import              FiniteCategory.FiniteCategory
+    import              Data.List                                       ((\\))
+    import              Data.Maybe                                      (fromJust)
+
+    (rcg1,newGen) = (mkRandomCompositionGraph 10 10 3 (mkStdGen 56767898))
+    
+    -- | We select an arrow in the category.
+    selectTwo = fromJust $ mkSelect2 rcg1 (fst (pickOne ((arrows rcg1)\\(identities rcg1)) newGen))
+
+    -- | Export the diagram as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleSelectTwoDiagram"
+        catToPdf rcg1 "OutputGraphViz/Examples/Diagram/SelectTwoDiagram/rcg1"
+        catToPdf (src selectTwo) "OutputGraphViz/Examples/Diagram/SelectTwoDiagram/Two"
+        diagToPdf selectTwo "OutputGraphViz/Examples/Diagram/SelectTwoDiagram/functor"
+        diagToPdf2 selectTwo "OutputGraphViz/Examples/Diagram/SelectTwoDiagram/diag"
+        putStrLn "End of ExampleSelectTwoDiagram"
+ test/ExampleDiagram/ExampleSelectZeroDiagram.hs view
@@ -0,0 +1,36 @@+{-| Module  : FiniteCategories
+Description : An example of select0 diagram.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of select0 diagram.
+-}
+module ExampleDiagram.ExampleSelectZeroDiagram
+(
+    selectZero,
+    main
+)
+where
+    import              RandomCompositionGraph.RandomCompositionGraph
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz                   (catToPdf,diagToPdf,diagToPdf2)
+    import              Diagram.Diagram                                 (mkSelect0, src)
+
+    (rcg1,newGen) = (mkRandomCompositionGraph 10 10 3 (mkStdGen 56))
+    
+    -- | We select no object in the category.
+    selectZero = mkSelect0 rcg1 
+
+    -- | Export the diagram as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleSelectZeroDiagram"
+        catToPdf rcg1 "OutputGraphViz/Examples/Diagram/SelectZeroDiagram/rcg1"
+        catToPdf (src selectZero) "OutputGraphViz/Examples/Diagram/SelectZeroDiagram/Zero"
+        diagToPdf selectZero "OutputGraphViz/Examples/Diagram/SelectZeroDiagram/functor"
+        diagToPdf2 selectZero "OutputGraphViz/Examples/Diagram/SelectZeroDiagram/diag"
+        putStrLn "End of ExampleSelectZeroDiagram"
+        
+        
+ test/ExampleFunctorCategory/ExampleFunctorCategory.hs view
@@ -0,0 +1,47 @@+{-| Module  : FiniteCategories
+Description : An example of functor category.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of functor category.
+-}
+module ExampleFunctorCategory.ExampleFunctorCategory
+(
+    functorCategory,
+    main
+)
+where
+    import              RandomCompositionGraph.RandomCompositionGraph
+    import              System.Random                                   
+    import              ExportGraphViz.ExportGraphViz
+    import              FiniteCategory.FiniteCategory
+    import              FunctorCategory.FunctorCategory
+    import              Diagram.Diagram
+    import              UsualCategories.One
+    import              Utils.Sample
+    import              Data.Maybe
+
+    (rcg1,newGen) = (mkRandomCompositionGraph 5 10 3 (mkStdGen 87819))
+    
+    (ob1,newGen1) = (pickOne (ob rcg1) newGen)
+    -- diag1 = fromJust (mkSelect1 rcg1 ob1)
+    -- diag2 = mkIdentityDiagram rcg1
+    -- | The functor category C^1
+    functorCategory = FunctorCategory{sourceCat=One, targetCat=rcg1}
+    
+    recuNatToPdf [] = putStrLn "End of natural transformation export"
+    recuNatToPdf (x:xs) = do
+                            natToPdf x ("OutputGraphViz/Examples/FunctorCategory/nat"++show (length xs))
+                            recuNatToPdf xs
+
+    -- | Export the arrow category as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleFunctorCategory"
+        catToPdf rcg1 "OutputGraphViz/Examples/FunctorCategory/rcg"
+        catToPdf functorCategory "OutputGraphViz/Examples/FunctorCategory/functorCategory"
+        recuNatToPdf (arrows functorCategory)
+        putStrLn "End of ExampleFunctorCategory"
+        
+ test/ExampleOppositeCategory/ExampleOppositeCategory.hs view
@@ -0,0 +1,30 @@+{-| Module  : FiniteCategories
+Description : An example of opposite category.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of opposite category.
+-}
+module ExampleOppositeCategory.ExampleOppositeCategory
+(
+    opSet,
+    main
+)
+where
+    import              ExportGraphViz.ExportGraphViz          (catToPdf,genToPdf)
+    import              ExampleCat.ExampleCat         (set1)
+    import              OppositeCategory.OppositeCategory
+    -- | The opposite category of set1.
+    opSet = Op set1
+
+    -- | Export all the previously defined categories as pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleOppositeCategory"
+        catToPdf set1 "OutputGraphViz/Examples/OppositeCategory/set1"
+        catToPdf opSet "OutputGraphViz/Examples/OppositeCategory/opposite"
+        putStrLn "End of ExampleOppositeCategory"
+    
+        
+ test/ExampleParsers/Example.fscg view
@@ -0,0 +1,13 @@+<SRC>
+4
+1 -a-> 2 
+2 -b-> 3
+</SRC>
+
+<TGT>
+4
+Earth -gives birth to-> Apple tree -produces-> Apple -rots into-> Earth = <ID>
+</TGT>
+
+1 -a-> 2 => Earth -gives birth to-> Apple tree
+2 -b-> 3 => Apple tree -produces-> Apple
+ test/ExampleParsers/Example.scg view
@@ -0,0 +1,2 @@+4
+Earth -gives birth to-> Apple tree -produces-> Apple -rots into-> Earth = <ID>
+ test/ExampleParsers/Example2.scg view
@@ -0,0 +1,21 @@+#Max number of cycles :
+4
+
+#Objects :
+Apple
+Apple tree
+Earth
+
+# Arrows :
+#Apple -rots into-> Earth -gives birth to-> Apple tree -produces-> Apple
+#Apple -rots into-> Earth -gives birth to-> Apple tree
+Apple -rots into-> Earth
+Apple tree -produces-> Apple
+#Apple tree -produces-> Apple -rots into-> Earth -gives birth to-> Apple tree -produces-> Apple
+#Apple tree -produces-> Apple -rots into-> Earth -gives birth to-> Apple tree
+#Apple tree -produces-> Apple -rots into-> Earth
+#Earth -gives birth to-> Apple tree -produces-> Apple
+Earth -gives birth to-> Apple tree
+
+# Composition law :
+Earth -gives birth to-> Apple tree -produces-> Apple -rots into-> Earth = <ID>
+ test/ExampleParsers/ExampleSafeCompositionGraph.hs view
@@ -0,0 +1,30 @@+{-| Module  : FiniteCategories
+Description : Tests the parsing of scg files.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Tests the parsing of scg files.
+-}
+module ExampleParsers.ExampleSafeCompositionGraph
+(
+    main
+)
+where
+    import              IO.Parsers.Lexer
+    import              IO.Parsers.SafeCompositionGraph
+    import              CompositionGraph.SafeCompositionGraph
+    import              ExportGraphViz.ExportGraphViz
+
+    -- | Tests the parsing of scg files.
+    main = do 
+        putStrLn "Start of ExampleParsers.ExampleSafeCompositionGraph"
+        cg <- readSCGFile "test/ExampleParsers/Example.scg"
+        catToPdf cg "OutputGraphViz/Examples/Parsers/safeCompositionGraph"
+        writeSCGFile cg "test/ExampleParsers/Example2.scg"
+        cg2 <- readSCGFile "test/ExampleParsers/Example2.scg"
+        catToPdf cg2 "OutputGraphViz/Examples/Parsers/safeCompositionGraph2"
+        putStrLn "End of ExampleParsers.ExampleSafeCompositionGraph"
+        
+ test/ExampleParsers/ExampleSafeCompositionGraphFunctor.hs view
@@ -0,0 +1,32 @@+{-| Module  : FiniteCategories
+Description : Tests the parsing of fscg files.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Tests the parsing of fscg files.
+-}
+module ExampleParsers.ExampleSafeCompositionGraphFunctor
+(
+    main
+)
+where
+    import              IO.Parsers.Lexer
+    import              IO.Parsers.SafeCompositionGraphFunctor
+    import              CompositionGraph.SafeCompositionGraph
+    import              ExportGraphViz.ExportGraphViz
+    import              Diagram.Conversion
+    import              Diagram.Diagram
+    import              IO.PrettyPrint
+
+    -- | Export the arrow category as a pdf with GraphViz.
+    main = do 
+        putStrLn "Start of ExampleSafeCompositionGraphFunctor"
+        diag <- readFSCGFile "test/ExampleParsers/Example.fscg"
+        putStrLn $ pprint diag
+        diagToPdf2 diag "OutputGraphViz/Examples/Parsers/SafeCompositionGraphFunctor/diag"
+        putStrLn "End of ExampleSafeCompositionGraphFunctor"
+        
+        
+ test/ExampleProductCategory/ExampleProductCategory.hs view
@@ -0,0 +1,51 @@+{-| Module  : FiniteCategories
+Description : An example of product category.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of product category.
+-}
+module ExampleProductCategory.ExampleProductCategory
+(
+    main
+)
+where
+    import              CompositionGraph.CompositionGraph
+    import              ExportGraphViz.ExportGraphViz           (catToPdf, diagToPdf, diagToPdf2)
+    import              FiniteCategory.FiniteCategory hiding    (f,g,h,i,j)
+    import              Data.Text                               (Text, pack)
+    import              ProductCategory.ProductCategory
+    
+    
+    f = (pack "A", pack "B", 1) :: Arrow Text Int
+    g = (pack "A", pack "C", 2) :: Arrow Text Int
+    h = (pack "B", pack "D", 3) :: Arrow Text Int
+    i = (pack "C", pack "D", 4) :: Arrow Text Int
+    
+    -- | A composition law defined by hand. 
+    myLaw = []
+            
+    myGraph = (pack.pure <$> ['A'..'D'], [f,g,h,i])
+    -- | An example of a composition graph
+    Right square = mkCompositionGraph myGraph myLaw
+    
+    j = (pack "X", pack "Y", 9) :: Arrow Text Int
+    -- | A composition law defined by hand. 
+    myLaw2 = []
+            
+    myGraph2 = (pack.pure <$> ['X'..'Y'], [j])
+    -- | An example of a composition graph
+    Right arrow = mkCompositionGraph myGraph2 myLaw2
+    
+    prod = ProductCategory square arrow
+    
+    -- | Exports the composition graphs and its Yoneda embedding as pdf files with GraphViz.
+    main = do
+            putStrLn "Start of ExampleProductCategory"
+            catToPdf square "OutputGraphViz/Examples/ProductCategory/square"
+            catToPdf arrow "OutputGraphViz/Examples/ProductCategory/arrow"
+            catToPdf prod "OutputGraphViz/Examples/ProductCategory/prod"
+            putStrLn "End of ExampleProductCategory"
+ test/ExampleRandomCompositionGraph/ExampleRandomCompositionGraph.hs view
@@ -0,0 +1,41 @@+{-| Module  : FiniteCategories
+Description : Examples of random composition graphs.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+This example shows how to use `mkRandomCompositionGraph`.
+-}
+
+module ExampleRandomCompositionGraph.ExampleRandomCompositionGraph
+(
+main
+)
+where
+    import CompositionGraph.CompositionGraph
+    import RandomCompositionGraph.RandomCompositionGraph
+    import System.Random
+    import ExportGraphViz.ExportGraphViz
+    
+    generateRGCs :: (RandomGen g) => Int -> g -> [CompositionGraph Int Int] -> ([CompositionGraph Int Int], g)
+    generateRGCs 0 gen cgs = (cgs,gen)
+    generateRGCs n gen cgs = ((newCG:end), finalGen)
+        where
+            (newCG,newGen) = (mkRandomCompositionGraph 10 15 5 gen)
+            (end,finalGen) = generateRGCs (n-1) newGen cgs
+
+    exportRCG :: [CompositionGraph Int Int] -> IO ()
+    exportRCG [] = putStrLn "End of ExampleRandomCompositionGraph"
+    exportRCG (cg:cgs) = do 
+        putStrLn (show (length cgs)++" rcg remaining...")
+        catToPdf cg ("OutputGraphViz/Examples/RandomCompositionGraph/RCG"++show (length cgs))
+        exportRCG cgs
+
+    -- | Exports 10 random composition graphs as pdf.
+    main = do
+        putStrLn "Start of ExampleRandomCompositionGraph"
+        exportRCG cgs
+        where
+            (cgs, g) = generateRGCs 10 (mkStdGen 745678765434567) []
+ test/ExampleRandomDiagram/ExampleRandomDiagram.hs view
@@ -0,0 +1,44 @@+{-| Module  : FiniteCategories
+Description : Examples of random diagrams.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+This example shows how to use `mkRandomDiagram`.
+-}
+
+module ExampleRandomDiagram.ExampleRandomDiagram
+(
+    main
+)
+where
+    import CompositionGraph.CompositionGraph
+    import RandomCompositionGraph.RandomCompositionGraph
+    import RandomDiagram.RandomDiagram
+    import System.Random
+    import ExportGraphViz.ExportGraphViz
+    import Diagram.Diagram
+    
+    generateRDiags 0 gen diags = (diags,gen)
+    generateRDiags n gen diags = ((diag:end), finalGen)
+        where
+            (diag,newGen) = (defaultMkRandomDiagram gen)
+            (end,finalGen) = generateRDiags (n-1) newGen diags
+
+    exportDiags [] = putStrLn "End of ExampleRandomDiagram"
+    exportDiags (diag:diags) = do 
+        putStrLn (show (length diags)++" random diagrams remaining...")
+        catToPdf (src diag) ("OutputGraphViz/Examples/RandomDiagram/RandomDefaultDiagram/src"++show (length diags))
+        catToPdf (tgt diag) ("OutputGraphViz/Examples/RandomDiagram/RandomDefaultDiagram/tgt"++show (length diags))
+        diagToPdf diag ("OutputGraphViz/Examples/RandomDiagram/RandomDefaultDiagram/funct"++show (length diags))
+        diagToPdf2 diag ("OutputGraphViz/Examples/RandomDiagram/RandomDefaultDiagram/diag"++show (length diags))
+        exportDiags diags
+
+    -- | Exports 5 random composition graphs as pdf.
+    main = do
+        putStrLn "Start of ExampleRandomDiagram"
+        exportDiags diags
+        where
+            (diags, g) = generateRDiags 5 (mkStdGen 745678765434567) []
+ test/ExampleRandomDiagram/ExampleRandomTriangle.hs view
@@ -0,0 +1,43 @@+{-| Module  : FiniteCategories
+Description : Examples of random triangle diagrams.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+This example shows how to use `mkRandomDiagram`.
+-}
+
+module ExampleRandomDiagram.ExampleRandomTriangle
+(
+    main
+)
+where
+    import CompositionGraph.CompositionGraph
+    import RandomCompositionGraph.RandomCompositionGraph
+    import RandomDiagram.RandomDiagram
+    import System.Random
+    import ExportGraphViz.ExportGraphViz
+    import UsualCategories.Three
+    
+    generateRDiags 0 gen diags = (diags,gen)
+    generateRDiags n gen diags = ((diag:end), finalGen)
+        where
+            (newCG,newGen) = (defaultMkRandomCompositionGraph gen)
+            (diag,newGen2) = (mkRandomDiagram Three newCG newGen)
+            (end,finalGen) = generateRDiags (n-1) newGen2 diags
+
+    exportDiags [] = putStrLn "End of ExampleRandomTriangle"
+    exportDiags (diag:diags) = do 
+        putStrLn (show (length diags)++" random triangles remaining...")
+        diagToPdf diag ("OutputGraphViz/Examples/RandomDiagram/RandomTriangles/funct"++show (length diags))
+        diagToPdf2 diag ("OutputGraphViz/Examples/RandomDiagram/RandomTriangles/diag"++show (length diags))
+        exportDiags diags
+
+    -- | Exports 5 random composition graphs as pdf.
+    main = do
+        putStrLn "Start of ExampleRandomTriangle"
+        exportDiags diags
+        where
+            (diags, g) = generateRDiags 5 (mkStdGen 745678765434567) []
+ test/ExampleSet/ExampleCompletion.hs view
@@ -0,0 +1,39 @@+{-| Module  : FiniteCategories
+Description : An example of set cat completion.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of set cat completion.
+-}
+module ExampleSet.ExampleCompletion
+(
+    main
+)
+where
+    import              Set.FinSet
+    import              ConeCategory.ConeCategory
+    import              ExportGraphViz.ExportGraphViz
+    import              Diagram.Diagram
+
+    -- | Constructs the limit of an arbitrary diagram in a set category.
+    main = do
+        putStrLn "Start of ExampleCompletion"
+        let set = Collection $ [singleton 1, singleton 2] :: FinSet Int
+        let c = FinSetCat $ toList set
+        
+        let Just diag = mkDiscreteDiagram c [singleton 1, singleton 2]
+        diagToPdf2 diag "OutputGraphViz/Examples/Set/diag"
+        
+        let coneCat = mkConeCategory diag
+        catToPdf coneCat "OutputGraphViz/Examples/Set/Completion/coneCat"
+        let (insertionFunctor, newDiag, newLimit) = constructLimit diag
+        diagToPdf2 newDiag "OutputGraphViz/Examples/Set/Completion/newDiag"
+        let newConeCat = mkConeCategory newDiag
+        catToPdf newConeCat "OutputGraphViz/Examples/Set/Completion/newConeCat"
+        let lim = limits newDiag
+        sequence $ (uncurry coneToPdf) <$> zip (coneToNaturalTransformation <$> lim) (("OutputGraphViz/Examples/Set/Completion/limit"++).show <$> [1..(length lim)])
+        putStrLn "End of ExampleCompletion"
+        
+ test/ExampleSet/ExampleOrdSet.hs view
@@ -0,0 +1,30 @@+{-| Module  : FiniteCategories
+Description : An example of set category.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of set category.
+-}
+module ExampleSet.ExampleOrdSet
+(
+    set,
+    main
+)
+where
+    import              Set.FinOrdSet                          (FinOrdSet(..))
+    import              Data.Set                               (fromList)
+    import              ExportGraphViz.ExportGraphViz          (catToPdf,genToPdf)
+
+    -- | A category with {1,2} and {1,2,3} as objects and applications as morphisms.
+    set = FinOrdSet [fromList [1,2], fromList [1,2,3]] :: FinOrdSet Int
+
+    -- | Export the category @set@ as a pdf with GraphViz.
+    main = do
+        putStrLn "Start of ExampleOrdSet"
+        catToPdf set "OutputGraphViz/Examples/Set/ordSet"
+        genToPdf set "OutputGraphViz/Examples/Set/ordSetGen"
+        putStrLn "End of ExampleOrdSet"
+        
+ test/ExampleSet/ExamplePowerOrdSet.hs view
@@ -0,0 +1,30 @@+{-| Module  : FiniteCategories
+Description : An example of a power set category.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of power set category.
+-}
+
+module ExampleSet.ExamplePowerOrdSet
+(
+    power,
+    main
+)
+where
+    import              Set.FinOrdSet                          (FinOrdSet(..), powerFinOrdSet)
+    import              Data.Set                               (Set(..), fromList)
+    import              ExportGraphViz.ExportGraphViz          (catToPdf,genToPdf)
+
+    -- | A category with all subsets of {1,2,3} as objects and applications as morphisms.
+    power = powerFinOrdSet $ fromList [1..3] :: FinOrdSet Int
+
+    -- | Export the power set of {1,2,3} as a pdf with GraphViz.
+    main = do
+        putStrLn "Start of ExamplePowerOrdSet"
+        catToPdf power "OutputGraphViz/Examples/Set/powerOrdSet"
+        putStrLn "End of ExamplePowerOrdSet"
+    
+ test/ExampleSet/ExamplePowerSet.hs view
@@ -0,0 +1,30 @@+{-| Module  : FiniteCategories
+Description : An example of a power set category.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of power set category.
+-}
+
+module ExampleSet.ExamplePowerSet
+(
+    powerSet,
+    main
+)
+where
+    import              Set.FinSet
+    import              ExportGraphViz.ExportGraphViz          (catToPdf,genToPdf)
+
+    -- | A category with all subsets of {1,2,3} as objects and applications as morphisms.
+    powerSet = powerFinSet $ Collection $ Elem <$> [1..3] :: FinSet Int
+    powerSetCat = FinSetCat $ toList powerSet
+
+    -- | Export the power set of {1,2,3} as a pdf with GraphViz.
+    main = do
+        putStrLn "Start of ExamplePowerSet"
+        catToPdf powerSetCat "OutputGraphViz/Examples/Set/powerSet"
+        putStrLn "End of ExamplePowerSet"
+    
+ test/ExampleSet/ExampleSet.hs view
@@ -0,0 +1,33 @@+{-| Module  : FiniteCategories
+Description : An example of set category.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of set category.
+-}
+module ExampleSet.ExampleSet
+(
+    set,
+    setCat,
+    main
+)
+where
+    import              Set.FinSet
+    import              ExportGraphViz.ExportGraphViz          (catToPdf,genToPdf)
+
+    -- | A set containing {1,2} and {1,2,3}.
+    set = Collection [Collection $ Elem <$> [1,2], Collection $ Elem <$> [1,2,3]] :: FinSet Int
+    
+    -- | The category containing {1,2} and {1,2,3} as objects.
+    setCat = FinSetCat $ toList set
+
+    -- | Export the category @set@ as a pdf with GraphViz.
+    main = do
+        putStrLn "Start of ExampleSet"
+        catToPdf setCat "OutputGraphViz/Examples/Set/set"
+        genToPdf setCat "OutputGraphViz/Examples/Set/setGen"
+        putStrLn "End of ExampleSet"
+        
+ test/ExampleSubcategories/ExampleFreeSubcategory.hs view
@@ -0,0 +1,30 @@+{-| Module  : FiniteCategories
+Description : An example of free subcategory.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of free subcategory.
+-}
+module ExampleSubcategories.ExampleFreeSubcategory
+(
+    freeSubcategory,
+    main
+) where
+    import ExampleSet.ExamplePowerOrdSet (power)
+    import Subcategories.FreeSubcategory
+    import Set.FinOrdSet
+    import ExportGraphViz.ExportGraphViz
+    import Data.Set
+    import FiniteCategory.FiniteCategory
+    
+    -- | Free subcategory generated by three maps in the set category containing {1,2}, {2,3} and {1,3}.
+    freeSubcategory = FreeSubcategory power [(ar power (fromList [1,2]) (fromList [2,3])) !! 0,(ar power (fromList [2,3]) (fromList [1,3])) !! 0,(ar power (fromList [1,3]) (fromList [1,2])) !! 0] :: FreeSubcategory (FinOrdSet Int) (FinOrdMap Int) (Set Int)
+    
+    -- | Exports previously defined categories as pdf files with GraphViz.
+    main = do
+        putStrLn "Start of ExampleFreeSubcategory"
+        catToPdf freeSubcategory "OutputGraphViz/Examples/Subcategories/freeSubcategory"
+        putStrLn "End of ExampleFreeSubcategory"
+ test/ExampleYonedaEmbedding/ExampleYonedaEmbedding.hs view
@@ -0,0 +1,60 @@+{-| Module  : FiniteCategories
+Description : An example of Yoneda embedding.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+An example of Yoneda embedding.
+-}
+module ExampleYonedaEmbedding.ExampleYonedaEmbedding
+(
+    main
+)
+where
+    import              CompositionGraph.CompositionGraph
+    import              ExportGraphViz.ExportGraphViz           (catToPdf, diagToPdf, diagToPdf2)
+    import              FiniteCategory.FiniteCategory hiding    (f,g,h,i)
+    import              Data.Text                               (Text, pack)
+    import              YonedaEmbedding.YonedaEmbedding
+    import              IO.PrettyPrint
+    import              Subcategories.Subcategory
+    import              Subcategories.FullSubcategory
+    import              Diagram.Diagram
+    import              Utils.AssociationList
+    
+    import              Set.FinSet
+    
+    import              OppositeCategory.OppositeCategory 
+
+    f = (pack "A", pack "B", 1) :: Arrow Text Int
+    g = (pack "A", pack "C", 2) :: Arrow Text Int
+    h = (pack "B", pack "D", 3) :: Arrow Text Int
+    i = (pack "C", pack "D", 4) :: Arrow Text Int
+    
+    -- | A composition law defined by hand. 
+    myLaw = []
+            
+    myGraph = (pack.pure <$> ['A'..'D'], [f,g,h,i])
+    -- | An example of a composition graph
+    Right square = mkCompositionGraph myGraph myLaw
+    
+    (yoneda, funct) = yonedaEmbedding square
+    
+    type YC = (CompositionGraph Text Int)
+    type YM = (CGMorphism Text Int)
+    type YO = Text
+    
+    emptySheaf = Diagram {src = Op square, tgt = tgt ((ob yoneda) !! 0), omap = functToAssocList (const emptyFinSet) (ob square), mmap = functToAssocList (const FinMap{codomain = emptyFinSet, finMap = []}) (arrows (Op square))}
+    
+    subTarget = (FullSubcategory (tgt funct) (emptySheaf:(((omap funct) !-!) <$> (ob (src funct))))) :: FullSubcategory (PreSheavesCategory YC YM YO) (PreSheavesNatTransfo YC YM YO) (PreSheaf YC YM YO)
+    
+    -- | Exports the composition graphs and its Yoneda embedding as pdf files with GraphViz.
+    main = do
+            putStrLn "Start of ExampleYonedaEmbedding"
+            catToPdf square "OutputGraphViz/Examples/YonedaEmbedding/square"
+            -- diagToPdf (minimalDiagram funct) "OutputGraphViz/Examples/YonedaEmbedding/yonedaEmbeddingAsFunct"
+            diagToPdf2 (fullDiagram funct) "OutputGraphViz/Examples/YonedaEmbedding/yonedaEmbedding"
+            catToPdf subTarget "OutputGraphViz/Examples/YonedaEmbedding/fullYonedaEmbedding"
+            putStrLn "End of ExampleYonedaEmbedding"
+ test/RunAllExamples.hs view
@@ -0,0 +1,107 @@+{-| Module  : FiniteCategories
+Description : Run all examples of the project.
+Copyright   : Guillaume Sabbagh 2021
+License     : GPL-3
+Maintainer  : guillaumesabbagh@protonmail.com
+Stability   : experimental
+Portability : portable
+
+Run all examples of the project. See results in the folder OutputGraphViz.
+-}
+
+module Main
+(
+    main
+)
+where
+    import qualified ExampleCompositionGraph.ExampleCompositionGraph  as ECG
+    import qualified ExampleSet.ExampleOrdSet  as OSET
+    import qualified ExampleSet.ExamplePowerOrdSet  as POSET
+    import qualified ExampleRandomCompositionGraph.ExampleRandomCompositionGraph as RCG
+    import qualified ExampleCat.ExampleCat as CAT
+    import qualified ExampleCat.ExamplePartialFinCat as PCAT
+    import qualified ExampleCat.ExampleFunctor as FUNCT
+    import qualified ExampleDiagram.ExampleConstantDiagram as CONSTDIAG
+    import qualified ExampleDiagram.ExampleDiscreteDiagram as DISCRETEDIAG
+    import qualified ExampleDiagram.ExampleSelectOneDiagram as SELECTONEDIAG
+    import qualified ExampleDiagram.ExampleSelectTwoDiagram as SELECTTWODIAG
+    import qualified ExampleDiagram.ExampleSelectThreeDiagram as SELECTTHREEDIAG
+    import qualified ExampleDiagram.ExampleSelectZeroDiagram as SELECTZERODIAG
+    import qualified ExampleDiagram.ExampleParallelDiagram as PARDIAG
+    import qualified ExampleDiagram.ExampleDiagram as DIAG
+    import qualified ExampleDiagram.ExampleIdentityDiagram as IDDIAG
+    import qualified ExampleCommaCategory.ExampleSliceCategory as SLICE
+    import qualified ExampleCommaCategory.ExampleCosliceCategory as COSLICE
+    import qualified ExampleCommaCategory.ExampleArrowCategory as ARROWCAT
+    import qualified ExampleFunctorCategory.ExampleFunctorCategory as FUNCTCAT
+    import qualified ExampleDiagonalFunctor.ExampleDiagonalFunctor as DIAGONAL
+    import qualified ExampleConeCategory.ExampleConeCategory as CONE
+    import qualified ExampleConeCategory.ExampleCoconeCategory as COCONE
+    import qualified ExampleConeCategory.ExampleLimit as LIMIT
+    import qualified ExampleConeCategory.ExampleColimit as COLIMIT
+    import qualified ExampleRandomDiagram.ExampleRandomDiagram as RANDDIAG
+    import qualified ExampleRandomDiagram.ExampleRandomTriangle as RANDTRIANGLE
+    import qualified ExampleCompositionGraph.ExampleFinSetToCompositionGraph as SETTOCG
+    import qualified ExampleCompositionGraph.ExampleCompositionGraphConstruction as CGCONSTRUCT
+    import qualified ExampleDiagram.ExampleConversion as CONVERT
+    import qualified ExampleCompositionGraph.ExampleSafeCompositionGraph as SCG
+    import qualified ExampleSubcategories.ExampleFreeSubcategory as FSC
+    import qualified ExampleParsers.ExampleSafeCompositionGraph as PSCG
+    import qualified ExampleParsers.ExampleSafeCompositionGraphFunctor as PFSCG
+    import qualified ExampleConeCategory.ExampleLeftCone as LCONE
+    import qualified ExampleOppositeCategory.ExampleOppositeCategory as OP
+    import qualified ExampleSet.ExamplePowerSet as PSET
+    import qualified ExampleSet.ExampleSet as SET
+    import qualified ExampleYonedaEmbedding.ExampleYonedaEmbedding as YONEDA
+    import qualified ExampleSet.ExampleCompletion as COMP
+    import qualified ExampleProductCategory.ExampleProductCategory as PROD
+    import qualified ExampleCurrying.ExampleCurrying as CURRY
+    import qualified ExampleAdjunction.ExampleAdjunction as ADJ
+
+    -- | Run all examples of the project. See results in the folder OutputGraphViz.
+    main = do
+        ADJ.main
+        CURRY.main
+        PROD.main
+        COMP.main
+        YONEDA.main
+        SET.main
+        PSET.main
+        OP.main
+        LCONE.main
+        PFSCG.main
+        PSCG.main
+        FSC.main
+        SCG.main
+        CONVERT.main
+        CGCONSTRUCT.main
+        SETTOCG.main
+        PCAT.main
+        RCG.main
+        COLIMIT.main
+        LIMIT.main
+        COCONE.main
+        CONE.main
+        DIAGONAL.main
+        FUNCTCAT.main
+        ARROWCAT.main
+        COSLICE.main
+        SLICE.main
+        IDDIAG.main
+        DIAG.main
+        PARDIAG.main
+        SELECTZERODIAG.main
+        SELECTTHREEDIAG.main
+        SELECTTWODIAG.main
+        SELECTONEDIAG.main
+        DISCRETEDIAG.main
+        CONSTDIAG.main
+        FUNCT.main
+        CAT.main
+        ECG.main
+        OSET.main
+        POSET.main
+        RANDTRIANGLE.main
+        RANDDIAG.main
+        
+