2011-08-09 54 views
15

通常你有类似Applicative而没有pure,或类似Monad,但没有returnsemigroupoid包裹涵盖这些案件与ApplyBind。现在我处于类似的情况,涉及Arrow,我无法定义一个有意义的arr函数,但我认为其他函数会非常有意义。类型和箭头之间的类型类是否有意义?

我定义保存函数类型和它的反向功能:

import Control.Category 

data Rev a b = Rev (a -> b) (b -> a) 

reverse (Rev f g) = Rev g f 
apply (Rev f _) x = f x 
applyReverse (Rev _ g) y = g y 
compose (Rev f f') (Rev g g') = Rev ((Prelude..) f g) ((Prelude..) g' f') 

instance Category Rev where 
    id = Rev Prelude.id Prelude.id 
    (.) x y = compose x y 

现在我无法实现Arrow,但一些较弱:

--"Ow" is an "Arrow" without "arr" 
class Category a => Ow a where 
    first :: a b c -> a (b,d) (c,d) 
    first f = stars f Control.Category.id 

    second :: a b c -> a (d,b) (d,c) 
    second f = stars Control.Category.id f 

    --same as (***) 
    stars :: a b c -> a b' c' -> a (b,b') (c,c') 

... 
import Control.Arrow 

instance Ow Rev where 
    stars (Rev f f') (Rev g g') = Rev (f *** g) (f' *** g') 

我想我无法实现相当于&&&,因为它被定义为f &&& g = arr (\b -> (b,b)) >>> f *** g,而(\b -> (b,b))是不可逆的。不过,你认为这个较弱的类型可能有用吗?从理论的角度来看,它甚至是有意义的吗?

+0

是不是'箭头'功能完全是一个类别的定义? –

+0

不,“类别”功能是一个类别的定义。好吧,无论如何(也没有规律) - 据我了解,“类别”对应于** Hask **的子类别,它具有相同的对象(所有类型),但具有不同的态射。 “箭头”增加了更多的结构,但我不知道什么样的结构。 –

+0

@Antal S-Z:实际上不是子类别。 'Category'指定一个类别,其对象是** Hask **的对象,其中箭头由某个2-ary类型的构造函数给出。 'Functor'描述** Hask **的子类别,其箭头是** Hask **的对象,其中的对象由一些一元类型的构造函数给出。 'Applicative'将'(,)'的monoidal结构映射到'Functor',而'(&&&)'等映射到'Category'。 'arr'给出了一个函子,从** Hask **到'Category'。 –

回答

9

这种方法进行了探讨在“有然后再返回:箭可逆编程”:http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.153.9383

对于正是你正在运行到的原因,这竟然是没有捡到个不错的办法更广泛。最近,Tillmann Rendel提出了一种令人愉快的方法来替代biarrows的部分同构(http://www.informatik.uni-marburg.de/~rendel/rendel10invertible.pdf)。这已被封装在人们使用和玩玩:http://hackage.haskell.org/package/invertible-syntax

这就是说,我认为一个箭头没有arr作出一定的含义。我只是不认为这样的事情是捕捉可逆函数的适当工具。

编辑:还有Adam Megacz的广义箭头(http://www.cs.berkeley.edu/~megacz/garrows/)。这些对于可逆编程来说可能没有用(尽管基本的类型类似似乎是无足轻重的),但是它们确实在其他情况下使用,其他情况下arr太强,但其他箭头操作可能是有意义的。

8

从类别理论的角度来看,Category类型类描述了任何类别,其箭头可以通过类型构造函数直接在Haskell中描述。如果您可以使用全部函数来实现它,则几乎所有您希望在其之上构建的附加功能(以新的原始箭头或箭头构建函数的形式)在某种程度上都会有意义。唯一需要注意的是,增加表达能力可以打破其他要求,如arr经常发生的那样。

可逆函数的具体示例描述了一个类别,其中所有箭头都是同构的。在令人震惊的扭曲中,爱德华·凯米特已经在Hackage上拥有an implementation of this

arr函数大致相当于从Haskell函数到Arrow实例的函子(在类别理论意义上),使对象保持相同(即类型参数)。从Arrow简单地删除arr给你...别的东西,这可能不是非常有用的自己,没有至少增加等值的arr fstarr snd作为原语。

我认为,加入原语fstsnd,与(&&&)一起从两个输入端建立一个新的方向,应该给你products一类,这是从理论角度来看绝对明智的,以及不被与您使用的可逆箭头兼容,因为您找到的原因。

+0

没有原则性的方法来为'Rev'(或者'Iso',如果你愿意的话)编写'&&&'。你为什么问?因为'b - > a'和'c - > a'不能让你得到'(b,c) - > a',所以你的'a - > b'和'a - > c'是*两者都*保证退还您的原始'b'和'c'。 – sclv

+0

同样,你也不能为Iso编写正确的'fst'和'snd'! (a,b) - > a的倒数是什么?这就是为什么你需要部分同构。 (当然,你可以写一个'第一',然后'秒')。 – sclv

+0

@sclv:是的。事实上,'(***)'和'(+++)'都应该很好,以及赋予product/sum类型的关联性,交换性和分布性的函数。但是'(&&&)'和'(|||)'在一般情况下不起作用。 –

相关问题