В библиотеке, которую я пишу, мне показалось элегантным написать класс, похожий (но немного более общий), чем следующий, который сочетает в себе как обычные 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
Эдварда Кметта (ссылка выше), чтобы разобраться в подобных вещах, но в этом пакете fanin и uncurry разделены на классы CoCartesian и CCC соответственно.
Я немного читал о BiCCC, но еще не совсем в них разобрался.
Мои вопросы
Оправдана ли приведенная выше абстракция каким-то образом косым взглядом на теорию категорий?
Если да, то каким будет правильный язык, основанный на CT, для разговора о классе и его экземплярах?
EDIT: если это поможет, а приведенное выше упрощение искажает вещи: в моем реальном приложении я работаю с вложенными продуктами и сопутствующими продуктами, например. (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-арного кортежа uncurry, но наблюдение всех трех вместе выглядело как... что-то непроизвольное.
Обновить
Я обнаружил, что мышление с точки зрения алгебраических операций, а.ля Крис Тейлор types/" rel="nofollow noreferrer">блоги об "алгебре АТД". Это прояснило, что мой класс и методы на самом деле были просто законами экспоненты (и причиной, по которой мой последний экземпляр был неправильным).
Вы можете увидеть результат в моем пакете shapely-data
, в Exponent
и Base
; см. также исходный код для заметок и ненавязчивой разметки документа.