В библиотека, която пиша, открих, че е привидно елегантно да напиша клас, който е подобен на (но малко по-общ от) следния, който съчетава както обичайните uncurry
над продукти, така и функцията fanin
(от тук или тук, ако предпочитате):
{-# LANGUAGE TypeOperators, TypeFamilies,MultiParamTypeClasses, FlexibleInstances #-}
import Prelude hiding(uncurry)
import qualified Prelude
class Uncurry t r where
type t :->-> r
uncurry :: (t :->-> r) -> t -> r
instance Uncurry () r where
type () :->-> r = r
uncurry = const
instance Uncurry (a,b) r where
type (a,b) :->-> r = a -> b -> r
uncurry = Prelude.uncurry
instance (Uncurry b c, Uncurry a c)=> Uncurry (Either a b) c where
type Either a b :->-> c = (a :->-> c, b :->-> c)
uncurry (f,g) = either (uncurry f) (uncurry g)
Обикновено преглеждам пакета categories
на Edward Kmett (свързан по-горе), за да се ориентирам за подобни неща, но в този пакет имаме fanin и uncurry, разделени съответно на CoCartesian и CCC класове.
Прочетох малко за BiCCC, но все още не ги разбирам наистина.
Въпросите ми са
Горната абстракция оправдана ли е от някакъв начин на присвиване на теорията на категориите?
Ако е така, какъв би бил правилният език, основан на CT, за да се говори за класа и неговите екземпляри?
РЕДАКТИРАНЕ: В случай, че помага и опростяването по-горе изкривява нещата: в действителното си приложение работя с вложени продукти и съпродукти, напр. (1,(2,(3,())))
. Ето истинския код (въпреки че по скучни причини последният екземпляр е опростен и не работи сам, както е написан)
instance Uncurry () r where
type () :->-> r = r
uncurry = const
instance (Uncurry bs r)=> Uncurry (a,bs) r where
type (a,bs) :->-> r = a -> bs :->-> r
uncurry f = Prelude.uncurry (uncurry . f)
-- Not quite correct
instance (Uncurry bs c, Uncurry a c)=> Uncurry (Either a bs) c where
type Either a bs :->-> c = (a :->-> c, bs :->-> c)
uncurry (f,fs) = either (uncurry f) (uncurry fs) -- or as Sassa NF points out:
-- uncurry (|||)
Така че екземплярът const
за екземпляр ()
се появи естествено като рекурсивен основен случай за екземпляра на n-ary tuple uncurry, но виждането на трите заедно изглеждаше като... нещо непроизволно.
Актуализация
Открих това мислене от гледна точка на алгебрични операции, a.la Крис Тейлър блогове за "алгебрата на ADT". Правейки това изясни, че моят клас и методи наистина са просто законите на степента (и причината, поради която последният ми пример не беше правилен).
Можете да видите резултата в моя пакет shapely-data
, в Exponent
и Base
класове; вижте също източника за бележки и маркиране на док.