双向箭头
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.Category
和 Control.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)
我正在尝试使用箭头捕获对称数据处理管道,并且想知道双向组合是否可行。
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.Category
和 Control.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)