Haskell泛型具有独特的ID

时间:2013-12-04 23:27:03

标签: generics haskell types functional-programming

我已经使用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

1 个答案:

答案 0 :(得分: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 )
]