【问题标题】:Attach extra information at every level of a recursive data type?在递归数据类型的每个级别附加额外信息?
【发布时间】:2019-10-20 13:56:27
【问题描述】:

(这不是专门的 Haskell 问题。)

我有一个递归数据结构。我想在每个级别附加一些额外的信息。这是一个简化的示例,其中我将XY 添加到树的每个级别:

import Data.Functor.Foldable

data Wrap a = X a | Y a
  deriving Show

data TreeF a b = Leaf a | TreeF a b b
  deriving Show

depth1 :: Wrap (TreeF Int ())
depth1 = X (Leaf 1)

depth2 :: Wrap (TreeF Int (Wrap (TreeF Int ())))
depth2 = Y (TreeF 1 (X $ Leaf 1) (Y $ Leaf 1))

-- depthInfinity :: Fix something something ...

(TreeF 的定义对我来说是不自然的。我更愿意定义 data Tree a = Leaf a | Tree a (Tree a) (Tree a),但如果我这样做,我不知道如何陈述我的问题。所以我写了它以Base 函子的形式,也就是Data.Functor.Foldable。)

Wrap 类型可用于将信息XY 附加到某种数据。 depth1' 是一个深度 1 TreeF,其中 Wrap 标志已附加在每个级别(它只有一个级别)。 depth2 是一个深度为 2 的 TreeF,其中Wrap 标志已附加到每个级别(它有两个级别)。

如何创建任意深度的“环绕树”?我应该如何写它的类型签名?这种数据混搭有类别理论术语吗?

【问题讨论】:

    标签: haskell category-theory recursive-datastructures fixpoint-combinators


    【解决方案1】:

    你可以使用

    Fix (Compose Wrap (TreeF Int))
    

    但我可能不会。如果您确实想走开放递归路线,那么制作自己的Fix 变体可能是最明智的:

    data WrapData = X | Y
    data LabeledFix a f = Labeled a (f (LabeledFix a f))
    -- ... and then use LabeledFix WrapData (TreeF Int)
    

    但更明智的做法仍然是使用普通的旧封闭递归。您甚至不必使您的类型比以前更特别;只是:

    data Tree a = Leaf a | Branch a (Tree a) (Tree a)
    -- ... and then use Tree (WrapData, Int)
    

    【讨论】:

    • 我的例子很糟糕——事实上我正在使用的递归Expr 数据类型不是Functor(尽管现在我想知道它是否应该是)。因此,您最后的出色解决方案不适用。相反,我采用了类似于您的第二个建议的内容:我定义newtype ExprFWith b a = EFW (b, ExprF a) 其中ExprFExprFunctor,然后使用Fix (ExprFWith x) 在@ 的每个级别附加一个x 987654334@.
    • @JeffreyBenjaminBrown 如果你选择这条路线——也就是说,为你的基本函子制作一个修饰符,而不是修改后的Fix——那么我推荐type ExprFWith b = Compose ((,) b)。无需重新发明轮子!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-27
    • 2017-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多