问题
Description of loop from Control.Arrow:
The loop operator expresses computations in which an output value is fed back as input, although the computation occurs only once. It underlies the rec value recursion construct in arrow notation.
Its source code, and its instantiation for (->):
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
This immediately reminds me of fix, the fixpoint combinator:
fix :: (a -> a) -> a
fix f = let x = f x in x
So my question is:
- Is it possible to implement that particular
loopviafix? - How are their functionalities different?
回答1:
Well, of course. Every recursive definition can be written with
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,) . sndAnd it works the other way around:
fix f = loop (join (,) . f . snd) ()The above should convince you that
loopandfixare equivalently powerful when talking about(->). Why, then, if arrows are meant to generalize functions, isArrowLoopnot defined like so?class Arrow a => ArrowLoop a where fix :: a b b -> bArrows also generalize the notion of "process": when
Arrow a,a b cis a way to calculate acfrom ab. IfArrowLoopwas defined to directly generalizefix, then it would be severely crippled.fixwould have to "execute" the process without any context and directly produce a value of typeb, which means the "process"a b bcannot e.g. performIO. Or, consider the arrownewtype LT i o = LT { runLT :: [i] -> [o] }You’d like it if
fixwould produce a[b]from aLT b b, but it doesn’t.loopis a way around these restrictions. It takes a process as argument and produces a process as result. In a sense, all the context associated with the first process can be survived in the second, which would not be possible ifloopwere more likefix.Note that I can implement an analogue of
fixforArrowLoops:-- 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 generalBut I don't believe
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 cis implementable, so we can’t base
ArrowLooponfix'either.
来源:https://stackoverflow.com/questions/51758376/fix-vs-arrowloop