通过直接将定义和法律翻译成Haskell,我很开心学习类别理论。 Haskell当然不是Coq,但它帮助我获得了类别理论的直觉。我的问题是:以下是合理的"翻译" Haskell中一个类别的定义?
{-
The following definition of a category is adapted from "Basic Category Theory" by Jaap van Oosten:
A category is given by a collection of objects and a collection of morphisms.
Each morphism has a domain and a codomain which are objects.
One writes f:X->Y (or X -f-> Y) if X is the domain of the morphism f, and Y its codomain.
One also writes X = dom(f) and Y = cod(f)
Given two morphisms f and g such that cod(f) = dom(g), the composition
of f and g, written (g f), is defined and has domain dom(f) and codomain cod(g):
(X -f-> Y -g-> Z) = (X -(g f)-> Z)
Composition is associative, that is: given f : X -> Y , g : Y -> Z and h : Z -> W, h (g f) = (h g) f
For every object X there is an identity morphism idX : X -> X, satisfying
(idX g) = g for every g : Y -> X and (f idX) = f for every f : X -> Y.
-}
module Code.CategoryTheory where
---------------------------------------------------------------------
data Category o m =
Category
{
-- A category is given by a collection of objects and a collection of morphisms:
objects :: [o],
morphisms :: [m],
-- Each morphism has a domain and a codomain which are objects:
domain :: m -> o,
codomain :: m -> o,
-- Given two morphisms f and g such that codomain f = domain g,
-- the composition of f and g, written (g f), is defined:
compose :: m -> m -> Maybe m,
-- For every object X there is an identity morphism idX : X -> X
identity :: o -> m
}
---------------------------------------------------------------------
-- Check if (Category o m) is truly a category (category laws)
is_category :: (Eq o,Eq m) => Category o m -> Bool
is_category cat =
domains_are_objects cat
&& codomains_are_objects cat
&& composition_is_defined cat
&& composition_is_associative cat
&& identity_is_identity cat
---------------------------------------------------------------------
-- Each morphism has a domain and a codomain which are objects:
domains_are_objects :: Eq o => Category o m -> Bool
domains_are_objects cat =
all (\m -> elem (domain cat m) (objects cat)) (morphisms cat)
codomains_are_objects :: Eq o => Category o m -> Bool
codomains_are_objects cat =
all (\m -> elem (codomain cat m) (objects cat)) (morphisms cat)
---------------------------------------------------------------------
-- Given two morphisms f and g such that cod(f) = dom(g),
-- the composition of f and g, written (g f), is defined
-- and has domain dom(f) and codomain cod(g)
composition_is_defined :: Eq o => Category o m -> Bool
composition_is_defined cat =
go $ morphisms cat
where
go [] = True
go (m : mx) = all (go2 m) mx && go mx
go2 g f =
if domain cat g /= codomain cat f then
True
else
case compose cat g f of
Nothing -> False
Just gf -> domain cat gf == domain cat f && codomain cat gf == codomain cat g
---------------------------------------------------------------------
-- Composition is associative, that is:
-- given f:X->Y, g:Y->Z and h:Z->W, h (g f) = (h g) f
composition_is_associative :: (Eq o,Eq m) => Category o m -> Bool
composition_is_associative cat =
go $ morphisms cat
where
go [] = True
go (m : mx) = go2 m mx && go mx
go2 _ [] = True
go2 f (g : mx) = all (go3 f g) mx && go2 f mx
go3 f g h =
if codomain cat f == domain cat g && codomain cat g == domain cat h then
case (compose cat g f, compose cat h g) of
(Just gf, Just hg) ->
case (compose cat h gf, compose cat hg f) of
(Just hgf0, Just hgf1) -> hgf0 == hgf1
_ -> False
_ -> False
else
True
---------------------------------------------------------------------
-- For every object X there is an identity morphism idX : X -> X, satisfying
-- (idX g) = g for every g : Y -> X -- and (f idX) = f for every f : X -> Y.
identity_is_identity :: (Eq m,Eq o) => Category o m -> Bool
identity_is_identity cat =
go $ objects cat
where
go [] = True
go (o:ox) = all (go2 o) (morphisms cat) && go ox
go2 o m =
if domain cat m == o then
case compose cat m (identity cat o) of
Nothing -> False
Just mo -> mo == m
else if codomain cat m == o then
case compose cat (identity cat o) m of
Nothing -> False
Just im -> im == m
else
True
---------------------------------------------------------------------
instance (Show m,Show o) => Show (Category o m) where
show cat = "Category{objects=" ++ show (objects cat) ++ ",morphisms=" ++ show (morphisms cat) ++ "}"
---------------------------------------------------------------------
testCategory :: Category String (String,String,String)
testCategory =
Category
{
objects = ["A","B","C","D"],
morphisms = [("f","A","B"),("g","B","C"),("h","C","D"),("i","A","D")],
domain = \(_,a,_) -> a,
codomain = \(_,_,b) -> b,
compose = \(g,gd,gc) (f,fd,fc) ->
if fc /= gd then
Nothing
else if gd == gc then
Just (f,fd,fc)
else if fd == fc then
Just (g,gd,gc)
else
Just (g ++ "." ++ f,fd,gc),
identity = \o -> ("id" ++ show o, o, o)
}
---------------------------------------------------------------------
main :: IO ()
main = do
putStrLn "Category Theory"
let cat = testCategory
putStrLn $ show cat
putStrLn $ "Is category: " ++ show (is_category cat)
答案 0 :(得分:2)
这似乎并不是原始结构翻译的糟糕传递。但是你不能利用类型系统为你做任何检查。
数据类别包(https://hackage.haskell.org/package/data-category)使用一个巧妙的技巧来进行构建"一级升级"并强制执行态射等组成的某些属性......
核心是
class Category k where
src :: k a b -> Obj k a
tgt :: k a b -> Obj k b
(.) :: k b c -> k a b -> k a c
type Obj k a = k a a
在这里,他只代表态射及其构图,然后将对象简单地捕捉到这些物体上的身份态射。我发现这个库非常强大,可以表达它。