我一直在为WebAssembly指令定义GADT。许多这些指令构造函数具有相同的签名:
data Instruction result where
Add :: Instruction r -> Instruction r -> Instruction r
Sub :: Instruction r -> Instruction r -> Instruction r
Mul :: Instruction r -> Instruction r -> Instruction r
使用正常值,您可以简单地为这些二元运算符声明类型别名:
type Binop r = Instruction r -> Instruction r -> Instruction r
但是,当我在GADT定义中使用别名时:
{-# LANGUAGE GADTs #-}
module Data.Instruction where
type Binop r = Instruction r -> Instruction r -> Instruction r
data Instruction result where
Add :: Binop r
Sub :: Binop r
Mul :: Binop r
无法编译:
[6 of 6] Compiling Data.Instruction ( src/Data/Instruction.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/Data/Instruction.o )
.../src/Data/Instruction.hs:8:5: error:
• Data constructor ‘Add’ returns type ‘Binop r’
instead of an instance of its parent type ‘Instruction result’
• In the definition of data constructor ‘Add’
In the data type declaration for ‘Instruction’
|
11 | Add :: Binop r
| ^
有没有办法用GHC实现这一目标?如果没有,限制的原因是什么?
答案 0 :(得分:3)
可能,但不是你完成它的方式。这在这里有效:
type Foo = Bar Int
data Bar a where
Bar :: Foo
...因为Foo
确实具有Bar a
形式,a ~ Int
。但是,这并不是:
type Foo = Int -> Bar Int
data Bar a where
Bar :: Foo
它无法工作,因为GADT构造函数
data Bar a where
Bar :: Int -> Bar Int
实际上并未声明“可逆函数”Bar :: Int -> Bar Int
。相反,它声明如下:
data Bar' a = Bar' (a :~: Int) Int
即,它封装了a
参数类型实际为Int
的(运行时可读)证明。 GADT语法隐藏了这一点,但这意味着您不能在Int -> Bar Int
替换类型同义词,因为该类型同义词不知道如何封装此类型 - 质量证明。
......想一想,我不确定为什么我的第一个例子确实有效,因为它似乎遇到了同样的问题......