8

loop来自的说明Control.Arrow

循环运算符表示将输出值作为输入反馈的计算,尽管计算只发生一次。它是箭头符号中的 rec 值递归结构的基础。

它的源代码,以及它的实例化(->)

class Arrow a => ArrowLoop a where
    loop :: a (b,d) (c,d) -> a b c

instance ArrowLoop (->) where
    loop f b = let (c,d) = f (b,d) in c

这立即让我想起fix了定点组合器:

fix :: (a -> a) -> a
fix f = let x = f x in x

所以我的问题是:

  1. 是否有可能实现那个特定的loopvia fix
  2. 它们的功能有何不同?
4

1 回答 1

9
  1. 嗯,当然。每个递归定义都可以写成fix

    loop f b = let (c, d) = f (b, d) in c
    loop f b = fst $ let (c, d) = f (b, d) in (c, d)
    loop f b = fst $ let x = f (b, d) in x
    loop f b = fst $ let x = f' x in x
      where f' (_, d) = f (b, d)
    loop f b = fst $ fix $ f . (b,) . snd
    

    它反过来工作:

    fix f = loop (join (,) . f . snd) ()
    
  2. 上面应该说服你,loop并且fix在谈论(->). 那么,如果箭头是用来概括功能的,为什么ArrowLoop没有这样定义呢?

    class Arrow a => ArrowLoop a where
      fix :: a b b -> b
    

    箭头还概括了“过程”的概念:当Arrow a,是从 aa b c计算 a 的一种方法。如果被定义为直接泛化,那么它就会被严重削弱。将不得不在没有任何上下文的情况下“执行”该过程并直接产生一个 type 的值,这意味着“过程”不能例如 perform 。或者,考虑箭头cbArrowLoopfixfixba b bIO

    newtype LT i o = LT { runLT :: [i] -> [o] }
    

    如果会从 afix产生 a ,您会喜欢它,但事实并非如此。[b]LT b b

    loop是绕过这些限制的一种方法。它将过程作为参数并产生过程作为结果。从某种意义上说,与第一个过程相关的所有上下文都可以在第二个过程中保留下来,如果loop更像fix.

    请注意,我可以实现fixfor ArrowLoops 的类似物:

    -- resulting process ignores its input
    fix' :: ArrowLoop a -- taking an impl of loop as argument
         => a b b -> a u b
    fix' f = loop ((id &&& id) . f . arr snd)
    -- take off the outer application to () (application means (->), after all)
    -- and arrowify: join (,) = id &&& id; snd = arr snd; (Prelude..) = (Control.Category..)
    -- but the RHSs are more general
    

    但我不相信

    loop' :: Arrow a => (forall x u. a x x -> a u x) -- taking an impl of fix' as argument
          -> a (b, d) (c, d) -> a b c
    

    是可实现的,所以我们不能ArrowLoop基于fix'任何一个。

于 2018-08-09T05:04:42.323 回答