通常情况下,Applicative
没有pure
,或类似Monad
,但没有return
。 semigroupoid包使用Apply
和Bind
涵盖了这些案例。现在我处于类似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 :(得分:9)
这种方法在“有而且又回来了:可逆编程的箭头”中进行了探讨:http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.153.9383
正是由于你遇到的原因,这被证明是一种糟糕的方法,而这种方法并没有得到更广泛的应用。最近,蒂尔曼·伦德尔(Tillmann Rendel)对可逆语法产生了一种令人愉快的方法,该方法取代了双箭头的部分同构(http://www.informatik.uni-marburg.de/~rendel/rendel10invertible.pdf)。这已被包装在hackage上供人们使用和玩:http://hackage.haskell.org/package/invertible-syntax
那就是说,我认为没有arr
的箭头会产生一定的意义。我只是不认为这样的东西是捕捉可逆功能的适当工具。
编辑:还有Adam Megacz的广义箭头(http://www.cs.berkeley.edu/~megacz/garrows/)。这些对于可逆编程也许没有用(虽然基本的类型类似乎确实无法实现),但它们确实可用于arr
太强的其他情况,但其他箭头操作可能有意义。
答案 1 :(得分:8)
从类别理论的角度来看,Category
类型类描述了任何类别,其类型构造函数可以在Haskell中直接描述其箭头。如果您可以使用总函数实现它,那么您希望以新的原始箭头或箭头构建函数的形式构建的几乎任何其他功能在某种程度上都是有意义的。唯一需要注意的是,添加表达能力可以打破其他要求,就像arr
经常发生的那样。
您可逆函数的具体示例描述了一个所有箭头都是同构的类别。在完全和完全预期的令人震惊的扭曲中,爱德华·凯梅特已经有了an implementation of this的Hackage。
arr
函数大致相当于从Haskell函数到Arrow
实例的仿函数(在类别理论意义上),使对象保持相同(即类型参数)。只需从arr
中移除Arrow
即可为您提供其他内容,这可能本身并不是非常有用,至少不会添加等同于arr fst
和arr snd
的内容原语。
我认为添加fst
和snd
的基元以及(&&&)
来构建来自两个输入的新箭头,应该为您提供一个products的类别,从理论的角度来看是绝对明智的,并且由于你找到的原因而与你正在使用的可逆箭头不兼容。