【问题标题】:Use one Data Constructor into two different Types将一个数据构造函数用于两种不同的类型
【发布时间】:2022-01-25 06:47:02
【问题描述】:

现在我正在尝试使用 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 转换代码变得过于冗长。

【问题讨论】:

  • data RValue = LValue | Lit Int 怎么样?
  • hm.... 虽然它比 i 好(我想念这种方法)但是 LValue 真的是 RValue 的子集吗(在我看来,这个问题太重要了)?
  • 我只是按照您在开始时给出的定义进行了理解。右值:变量和文字,左值:仅变量。
  • 你想要什么,使用两种类型,你怎么知道Var "x"是什么类型?一个变量可能能够服务作为左值,但它不是一种左值。您正在将您的语言 的属性与您可以用您的语言 表示的对象混为一谈。
  • 这无疑是个好主意(而且比我自己发现的要好)。但我想知道它是“刚刚好”还是“最好的”?如果在“程序语言”中 RValue 真的是“LValue 和其他一些类型的值” - 它是“最好的”,并且问题 cat 被关闭。如果不是 - 我会尝试找到“主题区域对象在数据类型上匹配 1:1”的解决方案

标签: haskell types


【解决方案1】:

我实际上认为你的建议是最好的:

newtype LValue = Var String -- newtype is slightly better here, I think
data RValue = LValue LValue | Lit Int

几乎可以肯定的是,任何时候您将左值用作右值时,您都希望以统一的方式处理所有左值,因此您可能不需要或不想进行第二级模式匹配片刻;换句话说,我声称会比您最初预期的要少。

基本上有两种选择。首先是做一个类:

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 来构造LValues 或RValues。但是,在进行模式匹配时,您仍然需要在语法上区分它们。

第二个是做一个GADT:

data Side = L | R
data Value side where
    Var :: String -> Value side
    Lit :: String -> Value R

【讨论】:

  • >> 几乎可以肯定的是,任何时候您将左值用作右值时,您都希望以统一的方式处理所有左值谢谢@user1984。老实说,我以前没有想过这个问题,现在我意识到,这是一个案例(在关于 LValue 和 RValue 的大规模问题中)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-30
  • 1970-01-01
  • 2014-03-12
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
相关资源
最近更新 更多