在我编写的一个图书馆中,我发现编写一个类似于以下代码的类似物看起来非常优雅,它比通常的产品uncurry
和fanin
函数(从here或者如果你喜欢可以从here获取)更加通用:
{-# 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类。
我已经阅读了一些BiCCCs的内容,但还不太理解。
我的问题是:
上面的抽象是否有某种方式通过范畴论来证明?
如果是,那么正确的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 (|||)
因此,对于n元组的非柯里化实例,()
实例的const
实例自然而然地成为递归基本情况,但是看到所有三个实例在一起时,它们似乎是...某种非任意的东西。
更新
我发现,像Chris Taylor关于"ADT代数"的博客所说的那样,用代数运算的思路来考虑问题会更加清晰。这样做可以澄清我的类和方法实际上只是指数法则(也是为什么我的最后一个实例不正确的原因)。
你可以在我的shapely-data
包中看到结果,其中包括Exponent
和Base
类;还可以查看源代码以获取注释和非奇怪的文档标记。
(1,(2,(3,())))
,这就是()
实例的来源(这就是我所说的“更一般”的地方)。我将编辑我的答案,并附上真正的问题,如果您能看一下并提供更多见解,我会非常感激。 - jberryman- 现在
P a是一个嵌套的元组。我不确定如何使用
(,)而不是
PP`使其工作。 - Sassa NF(a -> r) -> ((a,()) -> r)
。 - jberrymantype RecursiveNestedEither a = Fix (Either a)
- 在共递归中非常有用的递归嵌套 Either 类型。 - Sassa NF