How do I use the Church encoding for Free Monads?

前端 未结 4 763
别跟我提以往
别跟我提以往 2021-02-08 10:49

I\'ve been using the Free datatype in Control.Monad.Free from the free package. Now I\'m trying to convert it to use F in

4条回答
  •  鱼传尺愫
    2021-02-08 11:16

    Let me describe the difference for a simpler scenario - lists. Let's focus on how one can consume lists:

    • By a catamorphism, which essentially means that we can express it using

      foldr :: (a -> r -> r) -> r -> [a] -> r
      

      As we can see, the folding functions never get hold of the list tail, only its processed value.

    • By pattern matching we can do somewhat more, in particular we can construct a generalized fold of type

      foldrGen :: (a -> [a] -> r) -> r -> [a] -> r
      

      It's easy to see that one can express foldr using foldrGen. However, as foldrGen isn't recursive, this expression involves recursion.

    • To generalize both concepts, we can introduce

      foldrPara :: (a -> ([a], r) -> r) -> r -> [a] -> r
      

      which gives the consuming function even more power: Both the reduced value of the tail, as well as the tail itself. Clearly this is more generic than both previous ones. This corresponds to a paramorphism which “eats its argument and keeps it too”.

    But it's also possible to do it the other way round. Even though paramorphisms are more general, they can be expressed using catamorphisms (at some overhead cost) by re-creating the original structure on the way:

    foldrPara :: (a -> ([a], r) -> r) -> r -> [a] -> r
    foldrPara f z = snd . foldr f' ([], z)
      where
        f' x t@(xs, r) = (x : xs, f x t)
    

    Now Church-encoded data structures encode the catamorphism pattern, for lists it's everything that can be constructed using foldr:

    newtype List a = L (forall r . r -> (a -> r -> r) -> r)
    
    nil :: List a
    nil = L $ \n _ -> n
    
    cons :: a -> List a -> List a
    cons x (L xs) = L $ \n c -> c x (xs n c)
    
    fromL :: List a -> [a]
    fromL (L f) = f [] (:)
    
    toL :: [a] -> List a
    toL xs = L (\n c -> foldr c n xs)
    

    In order to see the sub-lists, we have take the same approach: re-create them on the way:

    foldrParaL :: (a -> (List a, r) -> r) -> r -> List a -> r
    foldrParaL f z (L l) = snd $ l (nil, z) f'
      where
        f' x t@(xs, r) = (x `cons` xs, f x t)
    

    This applies generally to Church-encoded data structures, like to the encoded free monad. They express catamorphisms, that is folding without seeing the parts of the structure, only with the recursive results. To get hold of sub-structures during the process, we need to recreate them on the way.

提交回复
热议问题