将一个数据构造函数用于两种不同的类型
Use one Data Constructor into two different Types
现在我正在尝试使用 Haskell 编写一个玩具语言前端。
并且有两个实体:
- 右值 - 变量和整数文字(例如)
- 左值 - 仅限变量。
我认为在数据结构中最自然的描述方式是:
data LValue = Var String
data RValue = Var String | Lit Int
(我真的认为这是最好的方法——不冗长且不够严格,感谢详尽的模式匹配)
但是 ghc 向我显示错误:“多个 Var 声明”。
所以问题是:Haskell 中描述我想要的内容的最直接方式是什么?
注意事项:
11年前有一个类似的问题没有好的答案。但是11年有什么改变吗?
One value constructor belonging to two different types
还有一些其他方法在数据构造函数中再次“打包”LValue(并一次又一次地使用非玩具语言),如下所示:
data LValue = Var String
data RValue = LValue LValue | Lit Int
但我怀疑这是不是一个好方法:AST 转换代码变得过于冗长。
其实我觉得你的提议是最好的:
newtype LValue = Var String -- newtype is slightly better here, I think
data RValue = LValue LValue | Lit Int
几乎可以肯定的是,无论何时将左值用作右值,您都希望以统一的方式处理所有左值,因此您可能不需要或不想进行第二级模式匹配那一刻;换句话说,我声称会比您最初预期的要少冗长。
基本上有两种选择。首先是制作一个 class:
newtype LValue = LVar String
data RValue = RVar String | Lit Int
class HasVariables ty where var :: String -> ty
instance HasVariables LValue where var = LVar
instance HasVariables RValue where var = RVar
这样您就可以使用 var
来构建 LValue
或 RValue
。不过,在进行模式匹配时,您仍然需要在语法上区分它们。
二是制作GADT:
data Side = L | R
data Value side where
Var :: String -> Value side
Lit :: String -> Value R
现在我正在尝试使用 Haskell 编写一个玩具语言前端。
并且有两个实体:
- 右值 - 变量和整数文字(例如)
- 左值 - 仅限变量。
我认为在数据结构中最自然的描述方式是:
data LValue = Var String
data RValue = Var String | Lit Int
(我真的认为这是最好的方法——不冗长且不够严格,感谢详尽的模式匹配) 但是 ghc 向我显示错误:“多个 Var 声明”。
所以问题是:Haskell 中描述我想要的内容的最直接方式是什么?
注意事项: 11年前有一个类似的问题没有好的答案。但是11年有什么改变吗? One value constructor belonging to two different types
还有一些其他方法在数据构造函数中再次“打包”LValue(并一次又一次地使用非玩具语言),如下所示:
data LValue = Var String
data RValue = LValue LValue | Lit Int
但我怀疑这是不是一个好方法:AST 转换代码变得过于冗长。
其实我觉得你的提议是最好的:
newtype LValue = Var String -- newtype is slightly better here, I think
data RValue = LValue LValue | Lit Int
几乎可以肯定的是,无论何时将左值用作右值,您都希望以统一的方式处理所有左值,因此您可能不需要或不想进行第二级模式匹配那一刻;换句话说,我声称会比您最初预期的要少冗长。
基本上有两种选择。首先是制作一个 class:
newtype LValue = LVar String
data RValue = RVar String | Lit Int
class HasVariables ty where var :: String -> ty
instance HasVariables LValue where var = LVar
instance HasVariables RValue where var = RVar
这样您就可以使用 var
来构建 LValue
或 RValue
。不过,在进行模式匹配时,您仍然需要在语法上区分它们。
二是制作GADT:
data Side = L | R
data Value side where
Var :: String -> Value side
Lit :: String -> Value R