简体   繁体   English

如何使用Data.Reify来修改数据列表?

[英]how to reify a list of data using Data.Reify?

I tried to read the paper ( http://www.ittc.ku.edu/csdl/fpg/sites/default/files/Gill-09-TypeSafeReification.pdf ) and managed to reify my symbolic expression type, but I can't figure out how to reify a list of them. 我试着阅读这篇论文( http://www.ittc.ku.edu/csdl/fpg/sites/default/files/Gill-09-TypeSafeReification.pdf )并设法重新启用我的符号表达式类型,但我可以'弄清楚如何重新列出它们的清单。 Here's the simplified code: 这是简化的代码:

{-# OPTIONS_GHC -Wall #-}
{-# Language TypeOperators #-}
{-# Language TypeFamilies #-}
{-# Language FlexibleInstances #-}

import Control.Applicative
import Data.Reify

-- symbolic expression type
data Expr a = EConst a
            | EBin (Expr a) (Expr a)
            deriving Show

-- corresponding node type
data GraphExpr a b = GConst a
                   | GBin b b
                   deriving Show

instance MuRef (Expr a) where
  type DeRef (Expr a) = GraphExpr a
  mapDeRef _ (EConst c)  = pure (GConst c)
  mapDeRef f (EBin u v) = GBin <$> f u <*> f v

-- this works as expected
main :: IO ()
main = reifyGraph (EBin x (EBin x y)) >>= print
  where
    x = EConst "x"
    y = EConst "y"
-- (output: "let [(1,GBin 2 3),(3,GBin 2 4),(4,GConst "y"),(2,GConst "x")] in 1")

-- but what if I want to reify a list of Exprs?
data ExprList a = ExprList [Expr a]
data GraphList a b = GraphList [GraphExpr a b]

instance MuRef (ExprList a) where
  type DeRef (ExprList a) = GraphList a
  --  mapDeRef f (ExprList xs) = ???????

I had the exact same problem, and I found a solution using data-reify. 我有完全相同的问题,我找到了一个使用data-reify的解决方案。

The things you have to realise to arrive at a solution is that: 1. Even though the EDSL doesnt have lists, the graph type could contain them 2. It is possible to reify different types of data to the same result type. 为了得到解决方案,你必须意识到的事情是:1。即使EDSL没有列表,图表类型也可以包含它们2.可以将不同类型的数据统一到相同的结果类型。

So we start by adding list constructors to our result type: 所以我们首先在结果类型中添加列表构造函数:

data GraphExpr a b = GConst a
                   | GBin b b
                   | Cons b b
                   | Nil
                   deriving Show

Then we need a second instance of MuRef, that reifies lists of Expr a to GraphExpr. 然后我们需要MuRef的第二个实例,它将Expr a的列表统一到GraphExpr。

instance MuRef [Expr a] where
    type DeRef [Expr a] = GraphExpr a
    mapDeRef _ [] = pure Nil
    mapDeRef f (x:xs) = Cons <$> f x <*> f xs

Now with this in place, if we try to reify a list expression 现在有了这个,如果我们尝试重新列出一个列表表达式

reified = reifyGraph [EBin x (EBin x y), Ebin y (EBin x y)]
              where x = EConst "x"
                    y = EConst "y"

We'll get the result 我们会得到结果

let [(1,Cons 2 6),(6,Cons 7 9),(9,Nil),(7,GBin 5 8),(8,GBin 3 5),(2,GBin 3 4),(4,GBin 3 5),(5,GConst "y"),(3,GConst "x")] in 1

To extract the list of reified node-ids from this graph we can define a little function to walk the Conses and to extract the node-ids from them into a list. 要从此图中提取已知的节点ID列表,我们可以定义一个小函数来遍历Conses并将节点ID从它们提取到列表中。

walkConses :: Graph (GraphExpr t) -> [Unique]
walkConses (Graph xs root) = go (lookup root xs)
where 
    go (Just (Cons n1 n2)) = n1 : go (lookup n2 xs)
    go (Just Nil) = []

(If the graphs are huge, it might be a good idea to convert them to an IntMap before starting the walk) (如果图形很大,那么在开始漫步之前将它们转换为IntMap可能是个好主意)

This looks like a partial function, but since we know that the root of the DAG will always be a Cons-node (since we reify a list), and since we know that all node-ids are in xs this function will return a list of all node-ids in the result list. 这看起来像是一个部分函数,​​但是因为我们知道DAG的根将始终是Cons节点(因为我们重新列出了一个列表),并且因为我们知道所有node-id都在xs中,所以这个函数将返回一个列表结果列表中的所有node-id。

So if we run walkConses on our resulting graph we'll get the result: 因此,如果我们在结果图上运行walkConses,我们将得到结果:

[2, 7]

Hope this helps, I've been wrestling with this problem for a while too. 希望这会有所帮助,我也一直在努力解决这个问题。

You really can't do that with MuRef. 你真的不能用MuRef做到这一点。 GraphLists don't contain GraphLists. GraphLists不包含GraphLists。 You can reify each Expr in turn and write a one-off combinator to smash them into your GraphList though: 您可以依次重新启动每个Expr并编写一个一次性组合器,将它们粉碎到您的GraphList中:

Just use traverse reifyGraph over the ExprList contents. 只需在ExprList内容上使用遍历reifyGraph。

Also, both of the latter should probably be newtypes. 此外,后者都应该是新类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM