在我正在编写的库中,我发现编写一个与以下类似(但比稍微更通用)的类似乎很优雅,它结合了通常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)
我通常浏览 Edward Kmett 的categories
包(上面链接)来了解我对这类事情的看法,但在那个包中,我们将 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 元组 uncurry 实例的递归基本情况自然而然地出现,但是将这三个实例放在一起看起来像是……非任意的。
更新
我发现从代数运算的角度思考,a.la Chris Taylor关于“ADT 的代数”的博客。这样做澄清了我的类和方法实际上只是指数定律(以及我最后一个实例不正确的原因)。
你可以在我的shapely-data
包中,在Exponent
和Base
类中看到结果;另请参阅注释和非古怪文档标记的来源。