mirror of
https://github.com/Jaxan/ons-hs.git
synced 2025-04-26 22:27:45 +02:00
Initial commit
This commit is contained in:
commit
9d41629a3b
11 changed files with 545 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
.stack-work
|
||||
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017 Joshua Moerman
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
31
README.md
Normal file
31
README.md
Normal file
|
@ -0,0 +1,31 @@
|
|||
# ons-hs
|
||||
|
||||
Experimental implemtation of the ONS library in Haskell. It provides the basic
|
||||
notion of nominal sets and maps, and their manipulations (over the total order
|
||||
symmetry). It is implemented by instantiating the known representation theory,
|
||||
which turns out to be quite easy for the total order symmetry.
|
||||
|
||||
Nominal sets are structured possibly-infinite sets. They have symmetries which
|
||||
make them finitely representable. They can be used, for example, to define
|
||||
infinite state systems (nominal automata). Consequently, one can then do
|
||||
reachability analysis, minimisation and other automata-theoretic constructions.
|
||||
Here we take nominal sets over the total order symmetry, which means that the
|
||||
data-values come from the rational numbers (or any other dense linear order).
|
||||
The symmetries which act upon the nominal sets are the monotone bijections on
|
||||
the rationals.
|
||||
|
||||
The library uses an interface similar to the one provided by
|
||||
[ONS](https://github.com/davidv1992/ONS). It provides basic instances and also
|
||||
allows custom types to be nominal. It is purely functional.
|
||||
|
||||
|
||||
## TODO
|
||||
|
||||
This will never be a fully fledged library. It is just for fun. Nevertheless, I
|
||||
wish to do the following:
|
||||
|
||||
* Provide generic instances
|
||||
* Figure out the right data-structures (List vs. Sets vs. Seqs vs. ...)
|
||||
* Cleanup
|
||||
* Examples
|
||||
* Tests
|
2
Setup.hs
Normal file
2
Setup.hs
Normal file
|
@ -0,0 +1,2 @@
|
|||
import Distribution.Simple
|
||||
main = defaultMain
|
6
app/Main.hs
Normal file
6
app/Main.hs
Normal file
|
@ -0,0 +1,6 @@
|
|||
module Main where
|
||||
|
||||
import Orbit
|
||||
|
||||
main :: IO ()
|
||||
main = putStrLn "Hello from App.hs"
|
44
ons-hs.cabal
Normal file
44
ons-hs.cabal
Normal file
|
@ -0,0 +1,44 @@
|
|||
name: ons-hs
|
||||
version: 0.1.0.0
|
||||
synopsis: Implementation of the ONS (Ordered Nominal Sets) library in Haskell
|
||||
description: Nominal sets are structured infinite sets. They have symmetries which make them finitely representable. This library provides basic manipulation of them for the total order symmetry. It includes: products, sums, maps and sets. Can work with custom data types.
|
||||
homepage: https://gitlab.science.ru.nl/moerman/ons-hs
|
||||
license: MIT
|
||||
license-file: LICENSE
|
||||
author: Joshua Moerman
|
||||
maintainer: haskell@joshuamoerman.nl
|
||||
copyright: Joshua Moerman
|
||||
category: Unclassified
|
||||
build-type: Simple
|
||||
extra-source-files: README.md
|
||||
cabal-version: >=1.10
|
||||
|
||||
library
|
||||
hs-source-dirs: src
|
||||
exposed-modules: EquivariantMap
|
||||
, EquivariantSet
|
||||
, Orbit
|
||||
build-depends: base >= 4.7 && < 5
|
||||
, containers
|
||||
default-language: Haskell2010
|
||||
|
||||
executable ons-hs-exe
|
||||
hs-source-dirs: app
|
||||
main-is: Main.hs
|
||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||
build-depends: base
|
||||
, ons-hs
|
||||
default-language: Haskell2010
|
||||
|
||||
test-suite ons-hs-test
|
||||
type: exitcode-stdio-1.0
|
||||
hs-source-dirs: test
|
||||
main-is: Spec.hs
|
||||
build-depends: base
|
||||
, ons-hs
|
||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||
default-language: Haskell2010
|
||||
|
||||
source-repository head
|
||||
type: git
|
||||
location: https://gitlab.science.ru.nl/moerman/ons-hs
|
119
src/EquivariantMap.hs
Normal file
119
src/EquivariantMap.hs
Normal file
|
@ -0,0 +1,119 @@
|
|||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE StandaloneDeriving #-}
|
||||
{-# LANGUAGE UndecidableInstances #-}
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
|
||||
module EquivariantMap where
|
||||
|
||||
import Data.Set (Set)
|
||||
import qualified Data.Set as Set
|
||||
import Data.Semigroup (Semigroup)
|
||||
import Data.Map (Map)
|
||||
import qualified Data.Map as Map
|
||||
|
||||
import EquivariantSet (EquivariantSet(EqSet))
|
||||
import Orbit
|
||||
|
||||
-- Very similar to EquivariantSet
|
||||
-- Some of the notes there apply here too
|
||||
newtype EquivariantMap k v = EqMap { unEqMap :: Map (Orb k) (Orb v, [Bool]) }
|
||||
|
||||
-- Need undecidableIntances for this
|
||||
deriving instance (Eq (Orb k), Eq (Orb v)) => Eq (EquivariantMap k v)
|
||||
deriving instance (Ord (Orb k), Ord (Orb v)) => Ord (EquivariantMap k v)
|
||||
deriving instance (Show (Orb k), Show (Orb v)) => Show (EquivariantMap k v)
|
||||
|
||||
-- Left biased...
|
||||
deriving instance Ord (Orb k) => Monoid (EquivariantMap k v)
|
||||
deriving instance Ord (Orb k) => Semigroup (EquivariantMap k v)
|
||||
|
||||
-- TODO: foldable / traversable
|
||||
-- TODO: adjust / alter / update
|
||||
-- TODO: *WithKey functions
|
||||
|
||||
-- Some helper functions
|
||||
-- TODO: don't export these
|
||||
|
||||
mapel :: (Orbit k, Orbit v) => k -> v -> (Orb v, [Bool])
|
||||
mapel k v = (toOrbit v, bv (Set.toAscList (support k)) (Set.toAscList (support v)))
|
||||
|
||||
bv :: [Rat] -> [Rat] -> [Bool]
|
||||
bv l [] = replicate (length l) False
|
||||
bv [] l = undefined -- Non-equivariant function
|
||||
bv (x:xs) (y:ys) = case compare x y of
|
||||
LT -> False : bv xs (y:ys)
|
||||
EQ -> True : bv xs ys
|
||||
GT -> undefined -- Non-equivariant function
|
||||
|
||||
mapelInv :: (Orbit k, Orbit v) => k -> (Orb v, [Bool]) -> v
|
||||
mapelInv x (oy, bv) = getElement oy (Set.fromAscList . fmap fst . Prelude.filter snd $ zip (Set.toAscList (support x)) bv)
|
||||
|
||||
|
||||
-- Query
|
||||
|
||||
null :: EquivariantMap k v -> Bool
|
||||
null (EqMap m) = Map.null m
|
||||
|
||||
member :: (Orbit k, Ord (Orb k)) => k -> EquivariantMap k v -> Bool
|
||||
member x (EqMap m) = Map.member (toOrbit x) m
|
||||
|
||||
lookup :: (Orbit k, Ord (Orb k), Orbit v) => k -> EquivariantMap k v -> Maybe v
|
||||
lookup x (EqMap m) = mapelInv x <$> Map.lookup (toOrbit x) m
|
||||
|
||||
|
||||
-- Construction
|
||||
|
||||
empty :: EquivariantMap k v
|
||||
empty = EqMap Map.empty
|
||||
|
||||
singleton :: (Orbit k, Orbit v) => k -> v -> EquivariantMap k v
|
||||
singleton k v = EqMap (Map.singleton (toOrbit k) (mapel k v))
|
||||
|
||||
insert :: (Orbit k, Orbit v, Ord (Orb k)) => k -> v -> EquivariantMap k v -> EquivariantMap k v
|
||||
insert k v (EqMap m) = EqMap (Map.insert (toOrbit k) (mapel k v) m)
|
||||
|
||||
delete :: (Orbit k, Ord (Orb k)) => k -> EquivariantMap k v -> EquivariantMap k v
|
||||
delete k (EqMap m) = EqMap (Map.delete (toOrbit k) m)
|
||||
|
||||
|
||||
-- Combine
|
||||
|
||||
-- Can be done with just Map.unionWith and without getElementE but is a bit
|
||||
-- harder (probably easier). Also true for related functions
|
||||
-- op should be equivariant!
|
||||
unionWith :: (Orbit k, Orbit v, Ord (Orb k)) => (v -> v -> v) -> EquivariantMap k v -> EquivariantMap k v -> EquivariantMap k v
|
||||
unionWith op (EqMap m1) (EqMap m2) = EqMap (Map.unionWithKey opl m1 m2)
|
||||
where opl ko p1 p2 = let k = getElementE ko in mapel k (mapelInv k p1 `op` mapelInv k p2)
|
||||
|
||||
intersectionWith :: (Orbit k, Orbit v1, Orbit v2, Orbit v3, Ord (Orb k)) => (v1 -> v2 -> v3) -> EquivariantMap k v1 -> EquivariantMap k v2 -> EquivariantMap k v3
|
||||
intersectionWith op (EqMap m1) (EqMap m2) = EqMap (Map.intersectionWithKey opl m1 m2)
|
||||
where opl ko p1 p2 = let k = getElementE ko in mapel k (mapelInv k p1 `op` mapelInv k p2)
|
||||
|
||||
|
||||
-- Traversal
|
||||
|
||||
-- f should be equivariant
|
||||
map :: (Orbit k, Orbit v1, Orbit v2) => (v1 -> v2) -> EquivariantMap k v1 -> EquivariantMap k v2
|
||||
map f (EqMap m) = EqMap (Map.mapWithKey f2 m)
|
||||
where f2 ko p1 = let k = getElementE ko in mapel k (f $ mapelInv k p1)
|
||||
|
||||
mapWithKey :: (Orbit k, Orbit v1, Orbit v2) => (k -> v1 -> v2) -> EquivariantMap k v1 -> EquivariantMap k v2
|
||||
mapWithKey f (EqMap m) = EqMap (Map.mapWithKey f2 m)
|
||||
where f2 ko p1 = let k = getElementE ko in mapel k (f k $ mapelInv k p1)
|
||||
|
||||
|
||||
-- Conversion
|
||||
|
||||
keysSet :: EquivariantMap k v -> EquivariantSet k
|
||||
keysSet (EqMap m) = EqSet (Map.keysSet m)
|
||||
|
||||
fromSet :: (Orbit k, Orbit v) => (k -> v) -> EquivariantSet k -> EquivariantMap k v
|
||||
fromSet f (EqSet s) = EqMap (Map.fromSet f2 s)
|
||||
where f2 ko = let k = getElementE ko in mapel k (f k)
|
||||
|
||||
|
||||
-- Filter
|
||||
|
||||
filter :: (Orbit k, Orbit v) => (v -> Bool) -> EquivariantMap k v -> EquivariantMap k v
|
||||
filter p (EqMap m) = EqMap (Map.filterWithKey p2 m)
|
||||
where p2 ko pr = let k = getElementE ko in p $ mapelInv k pr
|
103
src/EquivariantSet.hs
Normal file
103
src/EquivariantSet.hs
Normal file
|
@ -0,0 +1,103 @@
|
|||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE StandaloneDeriving #-}
|
||||
{-# LANGUAGE UndecidableInstances #-}
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
|
||||
module EquivariantSet where
|
||||
|
||||
import Data.Set (Set)
|
||||
import qualified Data.Set as Set
|
||||
import Data.Semigroup (Semigroup)
|
||||
|
||||
import Orbit
|
||||
|
||||
-- Given a nominal type, we can construct equivariant sets
|
||||
-- These simply use a set data structure from prelude
|
||||
-- This works well because orbits are uniquely represented
|
||||
-- Note that functions such as toList do not return an ordered
|
||||
-- list since the representatives are chosen arbitrarily.
|
||||
-- TODO: think about folds (and size)
|
||||
newtype EquivariantSet a = EqSet { unEqSet :: Set (Orb a) }
|
||||
|
||||
-- Need undecidableIntances for this
|
||||
deriving instance Eq (Orb a) => Eq (EquivariantSet a)
|
||||
deriving instance Ord (Orb a) => Ord (EquivariantSet a)
|
||||
deriving instance Show (Orb a) => Show (EquivariantSet a)
|
||||
|
||||
-- For these we rely on the instances of Set
|
||||
-- It defines the join semi-lattice structure
|
||||
deriving instance Ord (Orb a) => Monoid (EquivariantSet a)
|
||||
deriving instance Ord (Orb a) => Semigroup (EquivariantSet a)
|
||||
|
||||
|
||||
-- Query
|
||||
|
||||
null :: EquivariantSet a -> Bool
|
||||
null = Set.null . unEqSet
|
||||
|
||||
size :: EquivariantSet a -> Int
|
||||
size = Set.size . unEqSet
|
||||
|
||||
member :: (Orbit a, Ord (Orb a)) => a -> EquivariantSet a -> Bool
|
||||
member a = Set.member (toOrbit a) . unEqSet
|
||||
|
||||
isSubsetOf :: Ord (Orb a) => EquivariantSet a -> EquivariantSet a -> Bool
|
||||
isSubsetOf (EqSet s1) (EqSet s2) = Set.isSubsetOf s1 s2
|
||||
|
||||
|
||||
-- Construction
|
||||
|
||||
empty :: EquivariantSet a
|
||||
empty = EqSet Set.empty
|
||||
|
||||
singleOrbit :: Orbit a => a -> EquivariantSet a
|
||||
singleOrbit = EqSet . Set.singleton . toOrbit
|
||||
|
||||
insert :: (Orbit a, Ord (Orb a)) => a -> EquivariantSet a -> EquivariantSet a
|
||||
insert a = EqSet . Set.insert (toOrbit a) . unEqSet
|
||||
|
||||
delete :: (Orbit a, Ord (Orb a)) => a -> EquivariantSet a -> EquivariantSet a
|
||||
delete a = EqSet . Set.delete (toOrbit a) . unEqSet
|
||||
|
||||
|
||||
-- Combine
|
||||
|
||||
union :: Ord (Orb a) => EquivariantSet a -> EquivariantSet a -> EquivariantSet a
|
||||
union a b = EqSet $ Set.union (unEqSet a) (unEqSet b)
|
||||
|
||||
difference :: Ord (Orb a) => EquivariantSet a -> EquivariantSet a -> EquivariantSet a
|
||||
difference a b = EqSet $ Set.difference (unEqSet a) (unEqSet b)
|
||||
|
||||
intersection :: Ord (Orb a) => EquivariantSet a -> EquivariantSet a -> EquivariantSet a
|
||||
intersection a b = EqSet $ Set.intersection (unEqSet a) (unEqSet b)
|
||||
|
||||
-- This is the meat of the file!
|
||||
product :: (Orbit a, Orbit b) => EquivariantSet a -> EquivariantSet b -> EquivariantSet (a, b)
|
||||
product (EqSet sa) (EqSet sb) = EqSet . Set.fromDistinctAscList . concat
|
||||
$ Orbit.product <$> Set.toAscList sa <*> Set.toAscList sb
|
||||
|
||||
|
||||
-- Filter
|
||||
|
||||
-- f should be equivariant
|
||||
filter :: Orbit a => (a -> Bool) -> EquivariantSet a -> EquivariantSet a
|
||||
filter f (EqSet s) = EqSet . Set.filter (f . getElementE) $ s
|
||||
|
||||
|
||||
-- Map
|
||||
|
||||
-- precondition: f is equivariant
|
||||
-- Note that f may change the ordering
|
||||
map :: (Orbit a, Orbit b, Ord (Orb b)) => (a -> b) -> EquivariantSet a -> EquivariantSet b
|
||||
map f = EqSet . Set.map (toOrbit . f . getElementE) . unEqSet
|
||||
|
||||
-- f should also preserve order!
|
||||
mapMonotonic :: (Orbit a, Orbit b) => (a -> b) -> EquivariantSet a -> EquivariantSet b
|
||||
mapMonotonic f = EqSet . Set.mapMonotonic (toOrbit . f . getElementE) . unEqSet
|
||||
|
||||
|
||||
-- Conversion
|
||||
|
||||
toList :: Orbit a => EquivariantSet a -> [a]
|
||||
toList = fmap getElementE . Set.toList . unEqSet
|
||||
|
149
src/Orbit.hs
Normal file
149
src/Orbit.hs
Normal file
|
@ -0,0 +1,149 @@
|
|||
{-# LANGUAGE TypeFamilies #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE StandaloneDeriving #-}
|
||||
|
||||
module Orbit where
|
||||
|
||||
import Data.Set (Set)
|
||||
import qualified Data.Set as Set
|
||||
|
||||
-- We only need ordering on this structure
|
||||
-- I wrap it, because Rational is a type synonym
|
||||
newtype Rat = Rat { unRat :: Rational }
|
||||
deriving (Eq, Ord)
|
||||
|
||||
-- Just for debugging
|
||||
instance Show Rat where
|
||||
show (Rat r) = show r
|
||||
showsPrec n (Rat r) = showsPrec n r
|
||||
|
||||
-- A support is a set of rational numbers
|
||||
-- Can also be represented as sorted list/vector
|
||||
-- I should experiment with that, once I have some tests
|
||||
type Support = Set Rat
|
||||
|
||||
-- Type class indicating that we can associate orbits with elements
|
||||
-- In fact, it means that a is a nominal type
|
||||
class Orbit a where
|
||||
data Orb a :: *
|
||||
toOrbit :: a -> Orb a
|
||||
support :: a -> Support
|
||||
-- Precondition: size of set == index
|
||||
getElement :: Orb a -> Support -> a
|
||||
-- Size of least support
|
||||
index :: Orb a -> Int
|
||||
|
||||
-- Just some element
|
||||
getElementE :: Orbit a => Orb a -> a
|
||||
getElementE orb = getElement orb (Set.fromAscList . fmap (Rat . toRational) $ [1 .. index orb])
|
||||
|
||||
-- Rational numbers fit the bill
|
||||
instance Orbit Rat where
|
||||
data Orb Rat = OrbRational
|
||||
toOrbit _ = OrbRational
|
||||
support r = Set.singleton r
|
||||
getElement _ s
|
||||
| Set.null s = undefined
|
||||
| otherwise = Set.findMin s
|
||||
index _ = 1
|
||||
|
||||
deriving instance Show (Orb Rat)
|
||||
deriving instance Eq (Orb Rat)
|
||||
deriving instance Ord (Orb Rat)
|
||||
|
||||
-- Cartesian product of nominal sets as well
|
||||
-- TODO: replace [Ordering] with Vec Ordering if better
|
||||
instance (Orbit a, Orbit b) => Orbit (a, b) where
|
||||
data Orb (a,b) = OrbPair !(Orb a) !(Orb b) ![Ordering]
|
||||
toOrbit (a, b) = OrbPair (toOrbit a) (toOrbit b) (bla sa sb)
|
||||
where
|
||||
sa = Set.toAscList $ support a
|
||||
sb = Set.toAscList $ support b
|
||||
bla [] ys = fmap (const GT) ys
|
||||
bla xs [] = fmap (const LT) xs
|
||||
bla (x:xs) (y:ys) = case compare x y of
|
||||
LT -> LT : (bla xs (y:ys))
|
||||
EQ -> EQ : (bla xs ys)
|
||||
GT -> GT : (bla (x:xs) ys)
|
||||
support (a, b) = Set.union (support a) (support b)
|
||||
getElement (OrbPair oa ob l) s = (getElement oa $ toSet ls, getElement ob $ toSet rs)
|
||||
where
|
||||
(ls, rs) = partitionOrd fst . zip l . Set.toAscList $ s
|
||||
toSet = Set.fromAscList . fmap snd
|
||||
index (OrbPair _ _ l) = length l
|
||||
|
||||
deriving instance (Show (Orb a), Show (Orb b)) => Show (Orb (a, b))
|
||||
deriving instance (Eq (Orb a), Eq (Orb b)) => Eq (Orb (a, b))
|
||||
deriving instance (Ord (Orb a), Ord (Orb b)) => Ord (Orb (a, b))
|
||||
|
||||
-- Could be in prelude or some other general purpose lib
|
||||
partitionOrd :: (a -> Ordering) -> [a] -> ([a],[a])
|
||||
{-# INLINE partitionOrd #-}
|
||||
partitionOrd p xs = foldr (selectOrd p) ([], []) xs
|
||||
|
||||
selectOrd :: (a -> Ordering) -> a -> ([a], [a]) -> ([a], [a])
|
||||
selectOrd f x ~(ls, rs) = case f x of
|
||||
LT -> (x : ls, rs)
|
||||
EQ -> (x : ls, x : rs)
|
||||
GT -> (ls, x : rs)
|
||||
|
||||
-- Enumerate all orbits in a product
|
||||
-- In lexicographical order
|
||||
product :: (Orbit a, Orbit b) => Orb a -> Orb b -> [Orb (a, b)]
|
||||
product oa ob = OrbPair oa ob <$> prodStrings (index oa) (index ob)
|
||||
|
||||
prodStrings :: Int -> Int -> [[Ordering]]
|
||||
prodStrings 0 0 = [[]]
|
||||
prodStrings 0 n = [replicate n GT]
|
||||
prodStrings n 0 = [replicate n LT]
|
||||
prodStrings 1 1 = [[LT, GT], [EQ], [GT, LT]]
|
||||
prodStrings n m = ((LT :) <$> prodStrings (n-1) m)
|
||||
++ ((EQ :) <$> prodStrings (n-1) (m-1))
|
||||
++ ((GT :) <$> prodStrings n (m-1))
|
||||
|
||||
-- Also for sums
|
||||
instance (Orbit a, Orbit b) => Orbit (Either a b) where
|
||||
newtype Orb (Either a b) = OrbEither (Either (Orb a) (Orb b))
|
||||
toOrbit (Left a) = OrbEither (Left (toOrbit a))
|
||||
toOrbit (Right b) = OrbEither (Right (toOrbit b))
|
||||
support (Left a) = support a
|
||||
support (Right b) = support b
|
||||
getElement (OrbEither (Left oa)) s = Left (getElement oa s)
|
||||
getElement (OrbEither (Right ob)) s = Right (getElement ob s)
|
||||
index (OrbEither (Left oa)) = index oa
|
||||
index (OrbEither (Right ob)) = index ob
|
||||
|
||||
deriving instance (Show (Orb a), Show (Orb b)) => Show (Orb (Either a b))
|
||||
deriving instance (Eq (Orb a), Eq (Orb b)) => Eq (Orb (Either a b))
|
||||
deriving instance (Ord (Orb a), Ord (Orb b)) => Ord (Orb (Either a b))
|
||||
|
||||
-- Data structure for the discrete nominal sets
|
||||
-- with a trivial action.
|
||||
data Trivial a = Trivial { unTrivial :: a }
|
||||
|
||||
-- We need to remember the value!
|
||||
instance Orbit (Trivial a) where
|
||||
newtype Orb (Trivial a) = OrbTrivial a
|
||||
toOrbit (Trivial a) = OrbTrivial a
|
||||
support _ = Set.empty
|
||||
getElement (OrbTrivial a) _ = Trivial a
|
||||
index _ = 0
|
||||
|
||||
deriving instance Show a => Show (Orb (Trivial a))
|
||||
deriving instance Eq a => Eq (Orb (Trivial a))
|
||||
deriving instance Ord a => Ord (Orb (Trivial a))
|
||||
|
||||
-- Orbits themselves are trivial,
|
||||
-- but we need to keep track of the orbit
|
||||
instance Orbit a => Orbit (Orb a) where
|
||||
newtype Orb (Orb a) = OrbOrb (Orb a)
|
||||
toOrbit a = OrbOrb a
|
||||
support _ = Set.empty
|
||||
getElement (OrbOrb oa) _ = oa
|
||||
index _ = 0
|
||||
|
||||
-- These are funny looking...
|
||||
deriving instance Show (Orb a) => Show (Orb (Orb a))
|
||||
deriving instance Eq (Orb a) => Eq (Orb (Orb a))
|
||||
deriving instance Ord (Orb a) => Ord (Orb (Orb a))
|
66
stack.yaml
Normal file
66
stack.yaml
Normal file
|
@ -0,0 +1,66 @@
|
|||
# This file was automatically generated by 'stack init'
|
||||
#
|
||||
# Some commonly used options have been documented as comments in this file.
|
||||
# For advanced use and comprehensive documentation of the format, please see:
|
||||
# https://docs.haskellstack.org/en/stable/yaml_configuration/
|
||||
|
||||
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
|
||||
# A snapshot resolver dictates the compiler version and the set of packages
|
||||
# to be used for project dependencies. For example:
|
||||
#
|
||||
# resolver: lts-3.5
|
||||
# resolver: nightly-2015-09-21
|
||||
# resolver: ghc-7.10.2
|
||||
# resolver: ghcjs-0.1.0_ghc-7.10.2
|
||||
# resolver:
|
||||
# name: custom-snapshot
|
||||
# location: "./custom-snapshot.yaml"
|
||||
resolver: lts-9.10
|
||||
|
||||
# User packages to be built.
|
||||
# Various formats can be used as shown in the example below.
|
||||
#
|
||||
# packages:
|
||||
# - some-directory
|
||||
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
|
||||
# - location:
|
||||
# git: https://github.com/commercialhaskell/stack.git
|
||||
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
# extra-dep: true
|
||||
# subdirs:
|
||||
# - auto-update
|
||||
# - wai
|
||||
#
|
||||
# A package marked 'extra-dep: true' will only be built if demanded by a
|
||||
# non-dependency (i.e. a user package), and its test suites and benchmarks
|
||||
# will not be run. This is useful for tweaking upstream packages.
|
||||
packages:
|
||||
- .
|
||||
# Dependency packages to be pulled from upstream that are not in the resolver
|
||||
# (e.g., acme-missiles-0.3)
|
||||
# extra-deps: []
|
||||
|
||||
# Override default flag values for local packages and extra-deps
|
||||
# flags: {}
|
||||
|
||||
# Extra package databases containing global packages
|
||||
# extra-package-dbs: []
|
||||
|
||||
# Control whether we use the GHC we find on the path
|
||||
# system-ghc: true
|
||||
#
|
||||
# Require a specific version of stack, using version ranges
|
||||
# require-stack-version: -any # Default
|
||||
# require-stack-version: ">=1.5"
|
||||
#
|
||||
# Override the architecture used by stack, especially useful on Windows
|
||||
# arch: i386
|
||||
# arch: x86_64
|
||||
#
|
||||
# Extra directories used by stack for building
|
||||
# extra-include-dirs: [/path/to/dir]
|
||||
# extra-lib-dirs: [/path/to/dir]
|
||||
#
|
||||
# Allow a newer minor version of GHC than the snapshot specifies
|
||||
# compiler-check: newer-minor
|
2
test/Spec.hs
Normal file
2
test/Spec.hs
Normal file
|
@ -0,0 +1,2 @@
|
|||
main :: IO ()
|
||||
main = putStrLn "Test suite not yet implemented"
|
Loading…
Add table
Reference in a new issue