【问题标题】:Haskell generics with unique ids具有唯一 ID 的 Haskell 泛型
【发布时间】:2013-12-21 16:51:42
【问题描述】:

我使用 Uniplate 已经有一段时间了,但我发现它缺乏识别节点的能力,这让我的工作变得更加困难。是否有允许绝对 ID 的泛型实现?这是我希望这样的实现具有的一些 API 的示例:

universe :: (Data on) => on -> [(Id,on)] -- returns all sub nodes, with ids
children :: (Data on) => on -> [(Id,on)] -- returns all direct children, with ids
transformAbove :: (Data on) => (on -> on) -> Id -> on -> on -- applies a transformation to all nodes which are ancestors of the node with the given id

【问题讨论】:

  • 有趣的想法!如果您想自己构建它,我能给您的唯一帮助是查看 data-reify 包。
  • 您希望Id 的类型和值是什么?
  • 我希望Id ~ [Int],虽然如果我们提前知道D的最大分支B,我们也可以有Id ~ Int并且每个子id等于parent id * B + child index
  • 好的,对于单个标量,最好使用 Integer 而不是 Int,因为 id 以指数方式增长到树深度

标签: generics haskell types functional-programming


【解决方案1】:

这至少是前两个函数的部分解决方案。

{-# LANGUAGE GADTs #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NoMonomorphismRestriction #-}

module Main where
import Text.Show.Pretty

import Data.Data
import Data.Generics.Uniplate.Data

type Id = [Int]

indexed :: Data on => on -> [(Int, on)]
indexed tree = zip [0..] $ children tree

labeled :: Data on => on -> [(Id, on)]
labeled tree = ([], tree) : [ (x:xs, tree) | (x, subtree) <- indexed tree, (xs, tree)
                                                          <- labeled subtree ]

universeI :: Data on => on -> [(Id, on)]
universeI = labeled

childrenI :: Data a => a -> [(Id, [a])]
childrenI = labeled . children

对于二叉树,我们可以应用 childrenI:

data Tree a = Leaf a | Fork (Tree a) (Tree a)
  deriving (Eq, Ord, Show, Data, Typeable)

a :: Tree Int
a = Fork (Fork (Leaf 1) (Leaf 2)) (Fork (Leaf 3) (Leaf 4))

main = print $ childrenI a

并获得以下标签:

[ ( [] , Fork (Fork (Leaf 1) (Leaf 2)) (Fork (Leaf 3) (Leaf 4)) )
, ( [ 0 ] , Fork (Leaf 1) (Leaf 2) )
, ( [ 0 , 0 ] , Leaf 1 )
, ( [ 0 , 1 ] , Leaf 2 )
, ( [ 1 ] , Fork (Leaf 3) (Leaf 4) )
, ( [ 1 , 0 ] , Leaf 3 )
, ( [ 1 , 1 ] , Leaf 4 )
]

【讨论】:

  • 这种东西没有现成的包吗?
  • 不,这通常不是泛型库会提供的东西,因为它真的只在树状结构中才有意义。如果您需要此功能,您可以在 Uniplate 或 SYB 之上实现它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-17
相关资源
最近更新 更多