编写" Pretext"时的递归问题知道版本的Lens.para

时间:2017-06-18 07:16:14

标签: haskell recursion lens recursion-schemes

我一直在尝试构建Lens.para的替代品,它为para函数提供镜头上下文,因为它可以正常工作。但是,我似乎在某处的递归中出错了。

根据我对它的理解,Lens.para是递归代数数据类型中的一个paramorphism函数。也就是说,它使用plated并使用一个函数来爆炸选项列表,用于遍历"自相似语法空间"一段数据,一直使它的遍历数据上下文可用于它的工作。它的类型是Lens.Plated a => (a -> [r] -> r) -> a -> r,其中[r]是数据上下文值的列表,a是每个值的类型,镀层知道如何"查看"连续的水平。

非常简单的玩具示例数据类型I用于概念验证,如下所示:

data EExp a = ELit a | EAdd (EExp a) (EExp a) deriving (Show, Eq)

所以,这是我的代码,包括showOptions的现有工作版本和我的新版本showOptions',它使用我的自定义Lens.para paraApp }。不同之处在于,这个数据随着数据的传递而传递Pretext,以便稍后我可以调整我的代码,以便在需要时使用此Pretext来调整原始数据结构。

{-# LANGUAGE RankNTypes, TemplateHaskell, ExplicitForAll, DeriveDataTypeable, StandaloneDeriving #-}

module StepThree where

import qualified Control.Lens as Lens
import qualified Data.Data as DD
import qualified Data.Data.Lens as DDL
import qualified Data.Maybe as DM
import qualified Data.List as DL
import Text.Read (readMaybe)
import StepThreeGrammar (EExp(..), pretty, run)

import Control.Comonad.Store.Class (pos, peek, ComonadStore)
import Control.Lens.Internal.Context (Pretext(..), sell)

import qualified Language.Haskell.Interpreter as I
import Language.Haskell.Interpreter (Interpreter, GhcError(..), InterpreterError(..))

instance DD.Data a => Lens.Plated (EExp a)
deriving instance DD.Data a => DD.Data (EExp a)

eg3' :: EExp Int
eg3' = EAdd (EAdd (EAdd (EAdd (EAdd (ELit 11) (ELit 9)) (ELit 3)) (ELit 1)) (ELit 5)) (ELit 0)

showOptions :: (Lens.Plated a, Show a) => (a -> String) -> a -> [String]
showOptions showFn = Lens.para $ \a xs ->
    let
      sa = showFn a
      (_,is) = DL.mapAccumL mapAccumFn (0, sa) xs
    in
      sa : concat is
  where
    mapAccumFn (n, acc) x =
      let
        i = pfxIndex (head x) acc
      in
        ( (n+i+length (head x)
          , drop (i+length (head x)) acc)
        , map (replicate (n+i) ' ' ++) x)


showOptions' :: (Lens.Plated a, Show a) => (a -> String) -> a -> [String]
showOptions' showFn = paraApp $ \(a, ctx) xs ->
    let
      sa = showFn a
      (_, is) = DL.mapAccumL mapAccumFn (0, sa) xs
    in
      sa : concat is
  where
    mapAccumFn (n, acc) x =
      let
        i = pfxIndex (head x) acc
      in
        ( (n+i+length (head x)
          , drop (i+length (head x)) acc)
        , map (replicate (n+i) ' ' ++) x)

paraApp :: Lens.Plated a => ((a, Pretext (->) a a a) -> [r] -> r) -> a -> r
paraApp f x = go id (x, makePretextFocussingOnSelfFor x)
  where
    go p a =
      let p' = Lens.plate . p
          holes = Lens.holesOf p' x
      in f a (go p' <$> (map (\c -> (pos c, c)) holes))
    makePretextFocussingOnSelfFor x = Pretext ($ x)


pfxIndex :: Eq a => [a] -> [a] -> Int
pfxIndex x y = maybe 0 id (DL.findIndex (x `DL.isPrefixOf`) (DL.tails y))

如果我进入GHCi并执行以下代码,它会提供预期的输出:

*Main EditorTest StepThree Control.Lens> mapM_ putStrLn $ StepThree.showOptions show eg3'
EAdd (EAdd (EAdd (EAdd (EAdd (ELit 11) (ELit 9)) (ELit 3)) (ELit 1)) (ELit 5)) (ELit 0)
      EAdd (EAdd (EAdd (EAdd (ELit 11) (ELit 9)) (ELit 3)) (ELit 1)) (ELit 5)
            EAdd (EAdd (EAdd (ELit 11) (ELit 9)) (ELit 3)) (ELit 1)
                  EAdd (EAdd (ELit 11) (ELit 9)) (ELit 3)
                        EAdd (ELit 11) (ELit 9)
                              ELit 11
                                        ELit 9
                                                  ELit 3
                                                            ELit 1
                                                                      ELit 5
                                                                                ELit 0

对于我不想对上下文做任何事情(例如更新原始值的特定部分)的情况,这是好的。

因此,当我尝试更换功能时,会发生以下情况(它应与上述相同):

    *Main EditorTest StepThree Control.Lens> mapM_ putStrLn $ StepThree.showOptions' show eg3'
    EAdd (EAdd (EAdd (EAdd (EAdd (ELit 11) (ELit 9)) (ELit 3)) (ELit 1)) (ELit 5)) (ELit 0)
          EAdd (EAdd (EAdd (EAdd (ELit 11) (ELit 9)) (ELit 3)) (ELit 1)) (ELit 5)
                EAdd (EAdd (EAdd (ELit 11) (ELit 9)) (ELit 3)) (ELit 1)
                      EAdd (EAdd (ELit 11) (ELit 9)) (ELit 3)
                            EAdd (ELit 11) (ELit 9)
                                  ELit 11
                                            ELit 9
                                                      ELit 3
                                                      ELit 11
                                                             ELit 9
                                                                ELit 1
                                                                EAdd (ELit 11) (ELit 9)
                                                                      ELit 11
                                                                                ELit 9
                                                                                       ELit 3
                                                                                       ELit 11
                                                                                              ELit 9
                                                                          ELit 5
                                                                          EAdd (EAdd (ELit 11) (ELit 9)) (ELit 3)
                                                                                EAdd (ELit 11) (ELit 9)
                                                                                      ELit 11
                                                                                                ELit 9
                                                                                                          ELit 3
                                                                                                          ELit 11
                                                                                                                 ELit 9
                                                                                                                 ELit 1
                                                                                                                 EAdd (ELit 11) (ELit 9)
                                                                                                                       ELit 11
                                                                                                                                 ELit 9
                                                                                                                                        ELit 3
                                                                                                                                        ELit 11
                                                                                                                                               ELit 9
                                                                                    ELit 0
                                                                                    EAdd (EAdd (EAdd (ELit 11) (ELit 9)) (ELit 3)) (ELit 1)
                                                                                          EAdd (EAdd (ELit 11) (ELit 9)) (ELit 3)
                                                                                                EAdd (ELit 11) (ELit 9)
                                                                                                      ELit 11
                                                                                                                ELit 9
                                                                                                                          ELit 3
                                                                                                                          ELit 11
                                                                                                                                 ELit 9
                                                                                                                                    ELit 1
                                                                                                                                    EAdd (ELit 11) (ELit 9)
                                                                                                                                          ELit 11
                                                                                                                                                    ELit 9
                                                                                                                                                           ELit 3
                                                                                                                                                           ELit 11
                                                                                                                                                                  ELit 9
                                                                                                                                           ELit 5
                                                                                                                                           EAdd (EAdd (ELit 11) (ELit 9)) (ELit 3)
                                                                                                                                                 EAdd (ELit 11) (ELit 9)
                                                                                                                                                       ELit 11
                                                                                                                                                                 ELit 9
                                                                                                                                                                           ELit 3
                                                                                                                                                                           ELit 11
                                                                                                                                                                                  ELit 9
                                                                                                                                                                                  ELit 1
                                                                                                                                                                                  EAdd (ELit 11) (ELit 9)
                                                                                                                                                                                        ELit 11
                                                                                                                                                                                                  ELit 9
                                                                                                                                                                                                         ELit 3
                                                                                                                                                                                                         ELit 11
                                                                                                                                                                                                                ELit 9

显然我的某个地方的递归错了,但我无法解决。与往常一样,任何帮助将不胜感激。

如果您不熟悉Lens.para的原始定义,可以在https://hackage.haskell.org/package/lens-4.15.2/docs/src/Control.Lens.Plated.html#para

找到它

1 个答案:

答案 0 :(得分:0)

这让我走上了一段非常有趣的旅程,我还在继续。我非常确定答案在于创建一个新功能,将Lens.paraOf plate的功能与Lens.contexts的功能合并。至少我现在知道这个问题,更多关于Context和递归方案。我建议任何对编写此函数感兴趣的人都应该查看这些函数的来源。

所以,回答这个问题,递归中的错误在于我使用fmap(<$>)映射每一个 upper < / em>镜头结构 lower 部分中的每个子项。这意味着每个子树,而不是仅仅将递归到树的特定部分,就是将完整的递归到树的每个部分。

正确的实施将考虑到这一点。