Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- {-
- Actually, now that I look at it, confusing isn't actually that confusing. The main type involved is Curried (Yoneda f) (Yoneda f), which is basically forall r. Yoneda f (a -> r) -> Yoneda f r. This is basically a kind of difference list for Applicatives. And if you flatten the newtype noise, you get:
- -}
- -- Isomorphic to Curried (Yoneda f) (Yoneda f) a
- newtype CurrYo f a = CurrYo {
- runCurrYo :: forall r s. (forall t. ((a -> r) -> t) -> f t) -> (r -> s) -> f s
- }
- instance Functor (CurrYo f) where
- -- fmap f cu returns a CurrYo that fmaps (. f) onto the Yoneda-encoded
- -- argument before passing it to cu.
- fmap f (CurrYo cu) = CurrYo $ \y -> cu $ \c -> y $ \x -> c $ x . f
- {-# INLINE fmap #-}
- instance Applicative (CurrYo f) where
- -- pure a fmaps ($ a) onto its Yoneda argument.
- pure a = CurrYo $ \y c -> y $ \x -> c $ x a
- {-# INLINE pure #-}
- -- cf <*> ca fmaps (.) onto its Yoneda argument before passing
- -- it to cf, then passing the whole thing to ca. This ensures
- -- left-association.
- CurrYo cf <*> CurrYo ca = CurrYo $ \y -> ca $ cf $ \c -> y $ \x -> c $ \f -> x . f
- {-# INLINE (<*>) #-}
- -- liftCurrYo fa produces a CurrYo that <*>s fa onto the end of the
- -- Yoneda-encoded Applicative.
- liftCurrYo :: Applicative f => f a -> CurrYo f a
- liftCurrYo fa = CurrYo $ \y c -> y (c .) <*> fa
- {-# INLINE liftCurrYo #-}
- -- lowerCurrYo cu first lowers cu to a Yoneda f by passing it pure id,
- -- then lowers the Yoneda f to an f by passing it id.
- lowerCurrYo :: Applicative f => CurrYo f a -> f a
- lowerCurrYo (CurrYo cu) = cu (\c -> pure (c id)) id
- {-# INLINE lowerCurrYo #-}
- {-
- -- And with all this, confusing is simple. Lift the function from a -> f b to
- -- a -> CurrYo f b, traverse (using the CurrYo Applicative instance,
- -- which left-associates), and then lower it to an f t.
- confusing :: Applicative f => LensLike (CurrYo f) s t a b -> LensLike f s t a b
- confusing t = \f -> lowerCurrYo . t (liftCurrYo . f)
- -- This also suggests an alternate strategy for traverseByOf - since the
- -- CurrYo Applicative instance doesn't refer to the Applicative instance of the
- -- base f, using different lift and lower functions allows you to traverse using
- -- custom pure and (<*>) functions without using ReifiedApplicative.
- traverseByOf ::
- Traversal s t a b ->
- (forall x. x -> f x) ->
- (forall x y. f (x -> y) -> f x -> f y) ->
- (a -> f b) -> s -> f t
- traverseByOf t pur app = \f s -> runCurrYo (t (\a -> CurrYo $ \y c -> y (c .) `app` f a) s) (\c -> pur $ c id) id
- -- And similarly for sequenceByOf.
- sequenceByOf ::
- Traversal s t (f b) b ->
- (forall x. x -> f x) ->
- (forall x y. f (x -> y) -> f x -> f y) ->
- s -> f t
- sequenceByOf t pur app = \s -> runCurrYo (t (\a -> CurrYo $ \y c -> y (c .) `app` a) s) (\c -> pur $ c id) id
- -}
- {-
- EDIT: 2 years later, I realize that you can remove some of the function overhead being carried around by the Functor and Applicative instances, because it doesn't really use the second function of type r -> s. It's not a Curried (Yoneda f) (Yoneda f) anymore; it's just a Curried (Yoneda f) f, so you can't use the equivalent of the standard intance, but a custom instance isn't that hard to write. Adding this for posterity:
- -}
- -- The new Applicative used internally by confusing.
- newtype Confuse f a = Confuse { runConfuse :: forall r. (forall t. ((a -> r) -> t) -> f t) -> f r }
- -- The Functor and Applicative instances are a lot harder to describe now, but they're correct.
- instance Functor (Confuse f) where
- fmap f (Confuse m) = Confuse $ \y -> m $ \u -> y $ \c -> u $ c . f
- {-# INLINE fmap #-}
- -- You still chain the values by passing them into each other right-to-left, to assure left-association.
- instance Applicative (Confuse f) where
- pure a = Confuse $ \y -> y ($ a)
- {-# INLINE pure #-}
- liftA2 f (Confuse ma) (Confuse mb) = Confuse $ \y -> mb $ \t -> ma $ \u -> y $ \c -> u $ \a -> t $ c . f a
- {-# INLINE liftA2 #-}
- Confuse mf <*> Confuse ma = Confuse $ \y -> ma $ \t -> mf $ \u -> y $ \c -> u $ \f -> t $ c . f
- {-# INLINE (<*>) #-}
- -- Lift an Applicative into Confuse, by sticking a <*> fa onto the end of the chain.
- liftConfuse :: Applicative f => f a -> Confuse f a
- liftConfuse fa = Confuse $ \y -> y id <*> fa
- {-# INLINE liftConfuse #-}
- -- Lower a Confuse back into the base Applicative, using pure.
- lowerConfuse :: Applicative f => Confuse f a -> f a
- lowerConfuse (Confuse m) = m $ \c -> pure (c id)
- {-# INLINE lowerConfuse #-}
- -- And then confusing works much the same way.
- confusing :: Applicative f => LensLike (Confuse f) s t a b -> LensLike f s t a b
- confusing t = \f -> lowerConfuse . t (liftConfuse . f)
- {-# INLINE confusing #-}
- -- We still get to use Confuse to implement traverseByOf.
- traverseByOf ::
- LensLike (Confuse f) s t a b ->
- (forall x. x -> f x) ->
- (forall x y. f (x -> y) -> f x -> f y) ->
- LensLike f s t a b
- traverseByOf t pur app = \f s -> runConfuse (t (\a -> Confuse $ \y -> app (y id) (f a)) s) $ \y -> pur $ y id
- {-# INLINE traverseByOf #-}
- -- And sequenceByOf as well.
- sequenceByOf ::
- LensLike (Confuse f) s t (f b) b ->
- (forall x. x -> f x) ->
- (forall x y. f (x -> y) -> f x -> f y) ->
- s -> f t
- sequenceByOf t pur app = \s -> runConfuse (t (\fa -> Confuse $ \y -> app (y id) fa) s) $ \y -> pur $ y id
- {-# INLINE sequenceByOf #-}
Advertisement
Add Comment
Please, Sign In to add comment