Is it possible to write join down for Arrows, not ArrowApply?

断了今生、忘了曾经 提交于 2020-08-19 07:29:36

问题


I tried writing down joinArr :: ??? a => a r (a r b) -> a r b. I came up with a solution which uses app, therefore narrowing the a down to ArrowApply's:

joinArr :: ArrowApply a => a r (a r b) -> a r b
joinArr g = g &&& Control.Category.id >>> app

Is it possible to have this function written down for arrows?

My guess is no.

Control.Monad.join could have been a good stand-in for >>= in the definition of the Monad type class: m >>= k = join $ k <$> m.

Having joinArr :: Arrow a => a r (a r b) (a r b) on our hands, it would be possible to write down instance Arrow a => Monad (ArrowMonad a):

m >>= k = joinArr (k <$> m)

Please note that joinArr should be slightly tweaked to be able to deal with the wrapper. If we speak of ArrowApply:

joinArr :: ArrowApply a => ArrowMonad a (ArrowMonad a b) -> ArrowMonad a b
joinArr (ArrowMonad m) = ArrowMonad $
   m &&& Control.Category.id >>>
   first (arr (\x -> let ArrowMonad h = x in h)) >>> 
   app

instance ArrowApply a => Monad (ArrowMonad a) is already implemented in the source file.

I reckon this argument not to be the best one (if it is right).

Am I right? What is the more formal way to back this up (or disprove it)?


回答1:


I think the formal reason that you can’t implement a x (a x y) -> a x y using only Arrow is that this requires a notion of either application (as you tried) or currying, or rather uncurrying in this case:

uncurry :: a x (a y z) -> a (x, y) z

With that, joinArr is simply:

joinArr :: a x (a x y) -> a x y
joinArr f = dup >>> uncurry f
  where dup = id &&& id

But if we can’t implement this without apply, curry, or uncurry, that means that a must be a Cartesian closed category (CCC) because we need some notion of “exponential” or higher-order arrow, which ArrowApply gives us, but Arrow only gives us a Cartesian category. (And I believe ArrowApply is equivalent to Monad because Monad is a strong monad in a CCC.)

The closest you can get with only Arrow is an Applicative, as you saw in the definition of instance (Arrow a) => Applicative (ArrowMonad a), which happens to be equivalent in power to join in the Reader monad (since there join = (<*> id)), but not the stronger monadic join:

joinArr' :: a x (x -> y) -> a x y
joinArr' f = (f &&& id) >>> arr (uncurry ($))

Note that instead of a higher-order arrow here, a x (a x y), we just reuse the (->) type.



来源:https://stackoverflow.com/questions/62542607/is-it-possible-to-write-join-down-for-arrows-not-arrowapply

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!