在我正在编写的库中,我发现编写一个类似于(但稍微更通用)以下类的类似乎是优雅的,它结合了通常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 (|||)
因此const
实例的()
实例自然地作为n元元组uncurry实例的递归基本情况,但看到所有三个实例看起来像......非任意的。< / p>
更新
我发现用代数运算来思考a.la Chris Taylor的blogs about the "algebra of ADTs"。这样做澄清了我的课程和方法实际上只是指数法(以及我最后一个实例不正确的原因)。
您可以在我的shapely-data
包中查看Exponent
and Base
类中的结果;另请参阅注释的来源和非成功的doc标记。
答案 0 :(得分:10)
你的上一个Uncurry实例恰好是uncurry (|||)
,因此没有任何“更一般”的内容。
咖喱发现任何箭头f:A×B→C箭头咖喱 f :A→C B ,这样一个独特的箭头评估:C B ×B→C通勤。您可以将eval视为($)
。说“CCC”是“在这个类别中我们拥有所有产品,所有指数和终端对象”的简写 - 换句话说,curry适用于任何类型和haskell中的任何函数。成为CCC的一个重要结果是A = 1×A = A×1(或a
与(a,())
同构,与((),a)
同构。)
haskell中的不合理是相同过程的相反标签。我们从箭头f = uncurry g 开始。每对具有两个投影,因此proj 1 和curry f = g的组成给出C B 。由于我们讨论的是成分和产品,因此在CCC中展示为任何g:A→C B 定义了一个独特的不合格的 g 。在CCC中我们拥有所有产品,因此我们有C B ×B,可以证明是C。
特别是,召回A = A×1。这意味着任何函数A→B也是函数A×1→B。您还可以将其视为“对于任何函数A→B,有一个函数A×1→B”,通过无关紧要的证据证明,其中您的第一个实例只有一半(仅id
证明了这一点。)< / p>
我不会将最后一个实例称为“不合理”,就像定义currying一样。最后一个例子是联产品定义的结构 - 对于任何一对箭头f:A→C和g:B→C,有一个独特的箭头[f,g] :( A + B)→C。从这个意义上讲,它似乎是对界面的滥用 - 它是意义的概括,从“不合理”到“给予某些东西,给我一些东西”或“:->->
和haskell函数之间的真实对应”。也许,您可以将类重命名为Arrow。