diff --git a/purescript/canopy/.gitignore b/purescript/canopy/.gitignore
new file mode 100644
index 0000000..30efe19
--- /dev/null
+++ b/purescript/canopy/.gitignore
@@ -0,0 +1,10 @@
+/bower_components/
+/node_modules/
+/.pulp-cache/
+/output/
+/generated-docs/
+/.psc-package/
+/.psc*
+/.purs*
+/.psa*
+/.spago
diff --git a/purescript/canopy/README.md b/purescript/canopy/README.md
new file mode 100644
index 0000000..8764694
--- /dev/null
+++ b/purescript/canopy/README.md
@@ -0,0 +1,12 @@
+# Canopy
+
+This directory contains an (unfinished) attempt at writing a [Diplomacy](<https://en.wikipedia.org/wiki/Diplomacy_(game)>) adjudecation engine.
+
+## File structure
+
+| File                                 | Description                                                                    |
+| ------------------------------------ | ------------------------------------------------------------------------------ |
+| [Tagless.purs](./src/Tagless.purs)   | Experiments regarding tagless representations of inductive types               |
+| [Graph.purs](./src/Graph.purs)       | Simple directed-graph type                                                     |
+| [DipMap.purs](./src/DipMap.purs)     | Representation for diplomacy maps                                              |
+| [DipMap.purs](./src/Adjudecate.purs) | Types for logical propositions. The adjudecation logic was supposed to go here |
diff --git a/purescript/canopy/packages.dhall b/purescript/canopy/packages.dhall
new file mode 100644
index 0000000..411b457
--- /dev/null
+++ b/purescript/canopy/packages.dhall
@@ -0,0 +1,105 @@
+{-
+Welcome to your new Dhall package-set!
+
+Below are instructions for how to edit this file for most use
+cases, so that you don't need to know Dhall to use it.
+
+## Use Cases
+
+Most will want to do one or both of these options:
+1. Override/Patch a package's dependency
+2. Add a package not already in the default package set
+
+This file will continue to work whether you use one or both options.
+Instructions for each option are explained below.
+
+### Overriding/Patching a package
+
+Purpose:
+- Change a package's dependency to a newer/older release than the
+    default package set's release
+- Use your own modified version of some dependency that may
+    include new API, changed API, removed API by
+    using your custom git repo of the library rather than
+    the package set's repo
+
+Syntax:
+where `entityName` is one of the following:
+- dependencies
+- repo
+- version
+-------------------------------
+let upstream = --
+in  upstream
+  with packageName.entityName = "new value"
+-------------------------------
+
+Example:
+-------------------------------
+let upstream = --
+in  upstream
+  with halogen.version = "master"
+  with halogen.repo = "https://example.com/path/to/git/repo.git"
+
+  with halogen-vdom.version = "v4.0.0"
+  with halogen-vdom.dependencies = [ "extra-dependency" ] # halogen-vdom.dependencies
+-------------------------------
+
+### Additions
+
+Purpose:
+- Add packages that aren't already included in the default package set
+
+Syntax:
+where `<version>` is:
+- a tag (i.e. "v4.0.0")
+- a branch (i.e. "master")
+- commit hash (i.e. "701f3e44aafb1a6459281714858fadf2c4c2a977")
+-------------------------------
+let upstream = --
+in  upstream
+  with new-package-name =
+    { dependencies =
+       [ "dependency1"
+       , "dependency2"
+       ]
+    , repo =
+       "https://example.com/path/to/git/repo.git"
+    , version =
+        "<version>"
+    }
+-------------------------------
+
+Example:
+-------------------------------
+let upstream = --
+in  upstream
+  with benchotron =
+      { dependencies =
+          [ "arrays"
+          , "exists"
+          , "profunctor"
+          , "strings"
+          , "quickcheck"
+          , "lcg"
+          , "transformers"
+          , "foldable-traversable"
+          , "exceptions"
+          , "node-fs"
+          , "node-buffer"
+          , "node-readline"
+          , "datetime"
+          , "now"
+          ]
+      , repo =
+          "https://github.com/hdgarrood/purescript-benchotron.git"
+      , version =
+          "v7.0.0"
+      }
+-------------------------------
+-}
+let upstream =
+      https://github.com/purescript/package-sets/releases/download/psc-0.15.4-20221229/packages.dhall
+        sha256:a6af1091425f806ec0da34934bb6c0ab0ac1598620bbcbb60a7d463354e7d87c
+
+in  upstream
diff --git a/purescript/canopy/spago.dhall b/purescript/canopy/spago.dhall
new file mode 100644
index 0000000..a12eaa9
--- /dev/null
+++ b/purescript/canopy/spago.dhall
@@ -0,0 +1,17 @@
+{-
+Welcome to a Spago project!
+You can edit this file as you like.
+
+Need help? See the following resources:
+- Spago documentation: https://github.com/purescript/spago
+- Dhall language tour: https://docs.dhall-lang.org/tutorials/Language-Tour.html
+
+When creating a new Spago project, you can use
+`spago init --no-comments` or `spago init -C`
+to generate this file without the comments in this block.
+-}
+{ name = "my-project"
+, dependencies = [ "arrays", "console", "effect", "lists", "maybe", "prelude" ]
+, packages = ./packages.dhall
+, sources = [ "src/**/*.purs", "test/**/*.purs" ]
+}
diff --git a/purescript/canopy/src/Adjudecate.purs b/purescript/canopy/src/Adjudecate.purs
new file mode 100644
index 0000000..c83a7ac
--- /dev/null
+++ b/purescript/canopy/src/Adjudecate.purs
@@ -0,0 +1,120 @@
+module Canopy.Adjudecate where
+
+import Prelude
+
+import Control.Bind (bind)
+import Data.Foldable (class Foldable, any, foldMap, foldlDefault, foldrDefault)
+import Data.List (List(..))
+import Data.List as List
+import Data.Tuple.Nested (type (/\), (/\))
+import Partial.Unsafe (unsafeCrashWith)
+import Prim.Row (class Cons)
+
+type Index = Int
+
+data Proposition a
+  = False
+  | True
+  | Disj (Proposition a) (Proposition a)
+  | Conj (Proposition a) (Proposition a)
+  | Negation (Proposition a)
+  | Other a
+
+derive instance Functor Proposition
+
+instance Apply Proposition where
+  apply = ap
+
+instance Applicative Proposition where
+  pure = Other
+
+instance Bind Proposition where
+  bind (Other a) f = f a
+  bind False _ = False
+  bind True _ = True
+  bind (Negation p) f = Negation (bind p f)
+  bind (Conj l r) f = Conj (bind l f) (bind r f)
+  bind (Disj l r) f = Disj (bind l f) (bind r f)
+
+instance Foldable Proposition where
+  foldMap f (Other a) = f a
+  foldMap f (Disj l r) = foldMap f l <> foldMap f r
+  foldMap f (Conj l r) = foldMap f l <> foldMap f r
+  foldMap f (Negation p) = foldMap f p
+  foldMap _ _ = mempty
+
+  foldr = foldrDefault
+  foldl = foldlDefault
+
+instance Monad Proposition
+
+derive instance Eq a => Eq (Proposition a)
+
+simp :: forall a. Eq a => Proposition a -> Proposition a
+simp (Conj False _) = False
+simp (Conj _ False) = False
+simp (Disj True _) = True
+simp (Disj _ True) = True
+simp (Negation True) = False
+simp (Negation False) = True
+simp (Negation (Negation p)) = simp p
+simp (Conj l r) | l == r = simp l
+simp (Disj l r) | l == r = simp l
+simp (Negation (Disj l r)) = simp $ Conj (simp $ Negation l) (simp $ Negation r)
+simp (Negation (Conj l r)) = simp $ Disj (simp $ Negation l) (simp $ Negation r)
+simp (Conj l (Negation r)) | l == r = False
+simp (Disj l (Negation r)) | l == r = True
+simp (Negation p) = Negation (simp p)
+simp (Conj l r) = Conj (simp l) (simp r)
+simp (Disj l r) = Disj (simp l) (simp r)
+simp o = o
+
+-- Put this inside a proposition to have
+-- two wildcard (self and target)
+data BinaryWildcard = BSelf | BTarget | BRef Index
+
+-- Put this inside a proposition to have
+-- a single wildcard (target)
+data UnaryWildcard = UTarget | URef Index
+
+newtype Entry = Entry
+  -- Expression which must be true for us to also be true.
+  { requires :: Proposition Index
+
+  -- We can add arbitrary logic to entries already in the graph
+  , contributes :: List (Proposition BinaryWildcard)
+  }
+
+data MoveImplications
+  = Empty
+  | AddEntry Entry MoveImplications
+
+referencesSelf :: Proposition UnaryWildcard -> Boolean
+referencesSelf = any case _ of
+    URef 0 -> true
+    _ -> false
+
+applyContributions :: List (Proposition UnaryWildcard) -> MoveImplications -> MoveImplications
+applyContributions Nil Empty = Empty
+applyContributions (Cons contribution rest) (AddEntry entry implications) = AddEntry entry' (applyContributions rest implications')
+  where
+  entry' = ?e
+  implications' = ?i
+
+  contributions = implications # List.partition referencesSelf
+
+applyContributions _ _ = unsafeCrashWith "Different amounts of contributions and implications"
+
+
+resolveMoveImplications :: MoveImplications -> List Boolean
+resolveMoveImplications Empty = List.Nil
+resolveMoveImplications (AddEntry (Entry { requires, contributes }) implications) =
+  ?w
+  where
+  unaryContributions :: List (Proposition UnaryWildcard)
+  unaryContributions = contributes <#> \proposition -> do
+    wildcard <- proposition
+    case wildcard of
+      BTarget -> pure UTarget
+      BRef i -> pure $ URef i
+      BSelf -> map URef requires
diff --git a/purescript/canopy/src/DipMap.purs b/purescript/canopy/src/DipMap.purs
new file mode 100644
index 0000000..869b6ba
--- /dev/null
+++ b/purescript/canopy/src/DipMap.purs
@@ -0,0 +1,28 @@
+module Canopy.DipMap where
+
+import Canopy.Graph (Graph)
+import Data.List (List)
+import Data.Maybe (Maybe)
+
+newtype DipUnit c = DipUnit
+  { nation :: c
+  , isFleet :: Boolean
+  }
+
+newtype Territory c = Territory
+  { isSea :: Boolean
+  , unit :: Maybe (DipUnit c)
+  }
+
+type DipMap c = Graph (Territory c)
+
+-- Index in some DipMap
+type Loc = Int
+
+data Move
+  = Attack Loc
+  | Support Loc Loc
+  | Convoy Loc Loc
+  | Hold
+
+type DipMoves = List Move
diff --git a/purescript/canopy/src/Graph.purs b/purescript/canopy/src/Graph.purs
new file mode 100644
index 0000000..e856574
--- /dev/null
+++ b/purescript/canopy/src/Graph.purs
@@ -0,0 +1,25 @@
+module Canopy.Graph where
+
+import Prelude
+
+import Data.Array as Array
+import Data.List (List(..))
+
+newtype Node v = Node
+  { adjacentTo :: Array Index
+  , value :: v
+  }
+
+type Graph v = List (Node v)
+type Index = Int
+
+adjacentTo :: forall v. Node v -> Array Index
+adjacentTo (Node {adjacentTo}) = adjacentTo
+
+areAdjacent :: forall v. Index -> Index -> Graph v -> Boolean
+areAdjacent first second Nil = false
+areAdjacent first second whole@(Cons node graph)
+  | first == second = false
+  | first > second = areAdjacent second first whole
+  | first == 0 = Array.elem second (adjacentTo node)
+  | otherwise = areAdjacent (first - 1) (second - 1) graph
diff --git a/purescript/canopy/src/Main.purs b/purescript/canopy/src/Main.purs
new file mode 100644
index 0000000..5c18dca
--- /dev/null
+++ b/purescript/canopy/src/Main.purs
@@ -0,0 +1,10 @@
+module Main where
+
+import Prelude
+
+import Effect (Effect)
+import Effect.Console (log)
+
+main :: Effect Unit
+main = do
+  log "🍝"
diff --git a/purescript/canopy/src/Tagless.purs b/purescript/canopy/src/Tagless.purs
new file mode 100644
index 0000000..c3c0c24
--- /dev/null
+++ b/purescript/canopy/src/Tagless.purs
@@ -0,0 +1,52 @@
+module Canopy.Tagless where
+
+import Safe.Coerce (coerce)
+import Type.Proxy (Proxy(..))
+
+foreign import data Nat :: Type
+foreign import data S :: Nat -> Nat
+foreign import data Z :: Nat
+
+type FinDict f =
+  { fz :: forall (n :: Nat). f (S n)
+  , fs :: forall (n :: Nat). f n -> f (S n)
+  }
+
+type VecDict f a =
+  { empty :: f Z
+  , cons :: forall a (n :: Nat). a -> f n -> f (S n)
+  }
+
+type Fin n = forall f. Proxy f -> FinDict f -> f n
+type Vec n a = forall f. Proxy f -> VecDict f a -> f n
+
+newtype Const a b = Const a
+newtype IndexT a n = IndexT (Vec n a -> a)
+
+index :: forall n a. Fin n -> Const a n
+index  fin = ?f
+  where
+  firstStep :: IndexT a n
+  firstStep = fin (Proxy :: _ (IndexT a)) finDict
+
+  finDict :: FinDict (IndexT a)
+  finDict =
+    { fz: IndexT \vec -> caseZero vec
+    , fs: ?s
+    }
+    where
+      caseZero :: forall n. Vec (S n) a -> a
+      caseZero vec = coerce const
+         where 
+           const :: Const a (S n)
+           const = vec (Proxy :: _ (Const a)) dict
+
+           dict :: VecDict (Const a) a
+           dict = {
+              empty: ?e, 
+              cons: ?c
+             }
+
+
+test :: Vec _ String
+test = \_ d -> d.cons "hey" (d.cons "ho" d.empty)
diff --git a/purescript/canopy/test/Main.purs b/purescript/canopy/test/Main.purs
new file mode 100644
index 0000000..f91f98c
--- /dev/null
+++ b/purescript/canopy/test/Main.purs
@@ -0,0 +1,11 @@
+module Test.Main where
+
+import Prelude
+
+import Effect (Effect)
+import Effect.Class.Console (log)
+
+main :: Effect Unit
+main = do
+  log "🍝"
+  log "You should add some tests."