Is it possible to get all contexts of a Traversable lazily?

后端 未结 4 1868
一向
一向 2021-02-07 02:56

lens offers holesOf, which is a somewhat more general and powerful version of this hypothetical function:

holesList :: Traversable t
          =>         


        
4条回答
  •  自闭症患者
    2021-02-07 03:31

    Your existing solution calls runMag once for every branch in the tree defined by Ap constructors.

    I haven't profiled anything, but as runMag is itself recursive, this might slow things down in a large tree.

    An alternative would be to tie the knot so you're only (in effect) calling runMag once for the entire tree:

    data Mag a b c where
      One :: a -> Mag a b b
      Pure :: c -> Mag a b c
      Ap :: Mag a b (c -> d) -> Mag a b c -> Mag a b d
    
    instance Functor (Mag a b) where
      fmap = Ap . Pure
    
    instance Applicative (Mag a b) where
      pure = Pure
      (<*>) = Ap
    
    holes :: forall t a. Traversable t => t a -> t (a, a -> t a)
    holes = \t -> 
        let m :: Mag a b (t b)
            m = traverse One t 
        in fst $ go id m m
      where
        go :: (x -> y)
           -> Mag a (a, a -> y) z
           -> Mag a a x
           -> (z, x)
        go f (One a)    (One _)    = ((a, f), a)
        go _ (Pure z)   (Pure x)   = (z, x)
        go f (Ap mg mi) (Ap mh mj) = 
          let ~(g, h) = go (f . ($j)) mg mh
              ~(i, j) = go (f .   h ) mi mj
          in (g i, h j)
        go _ _ _ = error "only called with same value twice, constructors must match"
    

提交回复
热议问题