双向箭头

Bidirectional Arrow

我正在尝试使用箭头捕获对称数据处理管道,并且想知道双向组合是否可行。

Control.Arrow 暴露以下内容

-- | Left to right composition
(>>>) :: Category cat => cat a b -> cat b c -> cat a c 

-- | Right to left composition
(<<<) :: Category cat => cat b c -> cat a b -> cat a c 

我想要但不知道如何表达的是对的双向组合。类型是这样的。

(<^>) :: Category cat => cat (a,y) (b,z) -> cat (b,x) (c,y) -> cat (a,x) (c,z) 

每对的第一个元素从左到右组成,第二个元素从右到左组成。

这是一个涉及成对的前向和后向函数的类别示例。

{-# LANGUAGE TypeOperators, GADTs #-}

import Prelude hiding ((.))
import Data.Category
import Data.Category.Product

type C = (->) :**: (Op (->))

上面说 C (a,b) (c,d) 与一对 (a->c, d->b) 同构。以自然方式对类别中的"compose":前向函数向前组合,向后函数向后组合。

这里有两个例子:

f :: C (String, Bool) (Int, Char)
f = length :**: Op (=='a')

请注意如何将向后函数包装在 Op(属于 "opposite" 类别)中。

g :: C (Int, Char) ([Int], Maybe Char)
g = (\x->[x,x]) :**: Op (maybe 'X' id)

请注意 g 的 "source" 是 f 的 "target"。这确保了组合成为可能。

composed :: C (String, Bool) ([Int], Maybe Char)
composed = g . f

test :: ([Int], Bool)
test = case composed of
   (forward :**: Op backward) -> (forward "abcde", backward Nothing)
-- result: ([5,5],False)

在更实际的方面,请注意 Data.CategoryControl.Category 是不同的野兽 :-( 问题中提到的 Control.Arrow 库使用后者。

不过,也应该可以为 Control.Category 定义 Op:**:。也许它已经在某处被黑了 (?)。

一些进一步的方法,最好记录为单独的答案。

第一个施加 ArrowLoop 的附加约束,并使用递归箭头 do 符号定义。

但是,从数据流的角度来看,没有发生递归。

(<->) ∷ (ArrowLoop a) ⇒ a (b,f) (c,g) → a (c,e) (d,f) → a (b,e) (d,g)
(<->) f1 f2 = proc (b, e) → do
  rec
    (c,g) ← f1 ↢ (b,f)
    (d,f) ← f2 ↢ (c,e)
  returnA ↢ (d,g)

同样可以定义为

(<->) ∷ (ArrowLoop a) ⇒ a (b,f) (c,g) → a (c,e) (d,f) → a (b,e) (d,g)
(<->) f1 f2 = proc (b, e) → do
  rec
    (d,f) ← f2 ↢ (c,e)
    (c,g) ← f1 ↢ (b,f)
  returnA ↢ (d,g)

第二种方法没有:我还没有弄清楚这是否是明智的做法。

(<->) ∷ (Arrow a) ⇒ a (b,f) (c,g) → a (c,e) (d,f) → a (b,e) (d,g)
(<->) f1 f2 = proc (b, e) → do
  (c,_) ← f1 ↢ (b,undefined)
  (d,_) ← f2 ↢ (c,undefined)
  (_,f) ← f2 ↢ (undefined,e)
  (_,g) ← f1 ↢ (undefined,f)
  returnA ↢ (d,g)

以下与第二种方法相同,但在组合函数方面明确定义。

(<->) ∷ (Arrow a) ⇒ a (b,f) (c,g) → a (c,e) (d,f) → a (b,e) (d,g)
(<->) f g =
  let toFst x = (x,undefined)
      toSnd x = (undefined,x)
  in
    (arr toFst ⋙ f ⋙ arr fst ⋙ arr toFst ⋙ g ⋙ arr fst) ⁂
    (arr snd ⋘ f ⋘ arr toSnd ⋘ arr snd ⋘ g ⋘ arr toSnd)