Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 如何在将AST转换为图形(eDSL)时保留类型信息_Haskell_Dsl - Fatal编程技术网

Haskell 如何在将AST转换为图形(eDSL)时保留类型信息

Haskell 如何在将AST转换为图形(eDSL)时保留类型信息,haskell,dsl,Haskell,Dsl,我正在尝试创建一个简单的嵌入式DSL,它应该允许 递归定义。为此,我正在使用 将表达式的AST转换为图形 在下面的示例代码中,信号表示用户的AST 可以使用(请参阅测试信号)。它是静态类型的,所以不是 例如,可以添加一个双信号和一个信号Int {-# LANGUAGE GADTs, TypeFamilies #-} import Control.Applicative hiding (Const) import Data.Reify data Value = VFloat64 Double

我正在尝试创建一个简单的嵌入式DSL,它应该允许 递归定义。为此,我正在使用 将表达式的AST转换为图形

在下面的示例代码中,
信号
表示用户的AST 可以使用(请参阅
测试
信号)。它是静态类型的,所以不是
例如,可以添加一个
双信号
和一个
信号Int

{-# LANGUAGE GADTs, TypeFamilies #-}
import Control.Applicative hiding (Const)
import Data.Reify

data Value = VFloat64 Double
           | VFloat32 Float 
  deriving (Show)

class HasValue a where
    value :: a -> Value

instance HasValue Double where
    value x = VFloat64 x

instance HasValue Float where
    value x = VFloat32 x

data Signal t where
    Add :: Num t => Signal t -> Signal t -> Signal t
    Delay :: HasValue t => t -> Signal t -> Signal t
    Const :: HasValue t => t -> Signal t

data Node s where
    NodeAdd :: s -> s -> Node s
    NodeDelay :: Value -> s -> Node s
    NodeConst :: Value -> Node s
  deriving (Show)

instance MuRef (Signal t) where
    type DeRef (Signal t) = Node
    mapDeRef f (Add a b) = NodeAdd <$> f a <*> f b
    mapDeRef f (Const x) = pure $ NodeConst (value x)
    mapDeRef f (Delay x a) = NodeDelay (value x) <$> f a

test :: Signal Double
test = Add (Const 1.0) test
{-#语言GADT,类型族}
导入控制。应用程序隐藏(Const)
导入数据。具体化
数据值=VFloat64双精度
|VFloat32浮子
派生(显示)
类hasa值,其中
值::a->value
实例HasValue Double,其中
值x=VFloat64 x
实例HasValue Float,其中
值x=VFloat32 x
数据信号t在哪里
添加::Num t=>Signal t->Signal t->Signal t
延迟::HasValue t=>t->Signal t->Signal t
常量::HasValue t=>t->Signal t
数据节点在哪里
nodead::s->s->Node s
节点显示::值->节点->节点
NodeConst::Value->Node s
派生(显示)
实例MuRef(信号t),其中
类型DeRef(信号t)=节点
mapDeRef(addab)=nodead f a b
mapDeRef f(常数x)=纯$NodeConst(值x)
mapDeRef f(延迟x a)=节点显示(值x)f a
测试:双信号
测试=添加(常数1.0)测试
为了评估DSL,首先将AST转换为
节点
类型 使用
data-reify
中的
reifyGraph
。在目前的表述中,, 这涉及到使用
HasValue
typeclass转换值 将每个信号转换为总和类型
。不幸的是,这使得
节点
图形 有效地动态键入,因为要计算
nodead
,我将始终 必须检查两个参数是否使用相同的构造函数

所以我的问题是:是否有可能保留 在转换到
节点时,
信号
AST中仍然可用 图表

我已经尝试使用其他类型(即
节点sa
)参数化
节点

但这并没有奏效,因为
DeRef(Signal t)
需要是
*->*

类型,而不是使用类型类,为什么不像在其他地方那样使用GADTs为值标记类型

data Value v where 
  VFloat64 :: Double -> Value Double
  VFloat32 :: Float  -> Value Float 

deriving instance Show (Value v) 
在add构造函数中使用
Num t
现在是没有意义的-您现在知道
t
只能是
Float
Double

data Signal t where
    Add :: Signal t -> Signal t -> Signal t
    Delay :: Value t -> Signal t -> Signal t
    Const :: Value t -> Signal t
现在,与其扔掉标签,
Node
保留它们:

data Node t s
    = NodeAdd s s 
    | NodeDelay (Value t) s 
    | NodeConst (Value t)
  deriving Show
现在不需要
,因为您的AST已经包含
数据类型:

instance MuRef (Signal t) where
    type DeRef (Signal t) = Node t
    mapDeRef f (Add a b) = NodeAdd <$> f a <*> f b
    mapDeRef _ (Const x) = pure $ NodeConst x
    mapDeRef f (Delay x a) = NodeDelay x <$> f a

您是否可以在代码中包含求值部分(至少包括类型)?另外,您是否尝试过用
Node a s
代替
Node a
,这是否解决了
Deref(Signal t)
kind的问题?这可能有帮助吗?谢谢,这个包裹看起来很有趣。不幸的是,文档有点稀疏…抱歉,没有回答。周末我无法登录。你的答案回答了这个问题,所以我接受。
let test = Add (Const (VFloat64 1.0)) test

> :t reifyGraph test
  reifyGraph test :: IO (Graph (DeRef (Signal Double)))