6

在尝试用 Scala 中的代数数据类型描述 Sql 的一部分时,我遇到了创建表示数据类型的根特征的子特征的必要性。由于满足此要求产生了一个我不确定是否可以用 Haskell 的 ADT 表示的代码,并且由于与 Haskell 不同,ADT 不是 Scala 的本机构造,我现在想知道:

  1. 我是对的,在 Haskell 中不可能表示一个模型,例如一个Sql具有“子类型”的类型,并且在 HaskellStatement中有一个构造函数吗?(似乎可能是相关的)。Select
  2. 如果是这样,术语“ADT”是否适用于我生成的代码?
  3. 如果是的话,这是否使 Scala 在这方面实际上比 Haskell 更强大?
  4. 如果没有,这个功能没有在 Haskell 中实现的原因是什么?这让我觉得我的模型中的事情可能过于复杂

这是我正在谈论的模型:

sealed trait Sql


sealed trait Statement 
  extends Sql

sealed case class Union 
  ( left : Statement, 
    right : Statement ) 
  extends Statement

sealed case class Select
  ( /** other fields don't matter **/
    where : Where )
  extends Statement


sealed trait Where 
  extends Sql

sealed case class And
  ( left : Where,
    right : Where )
  extends Where

sealed case class Or
  ( left : Where,
    right : Where )
  extends Where

sealed case class Equals
  ( /** fields don't matter **/ )
  extends Where
4

3 回答 3

10

1.不,由于您的根特征是密封的,因此可以将呈现的层次结构表示为 ADT:

data Sql = Statement Statement | Where Where
        --           ^ This is the *type* called `Statement`
        -- ^ This is the *constructor* called `Statement`

data Statement = Union Statement Statement | Select Where

data Where = And Where Where | Or Where Where | Equals

在这种情况下是可能的,因为您可以枚举数据类型的所有“子类”(Sql在这种情况下),这使得将它们转换为 ADT 构造函数成为可能。如果您想允许用户任意添加“构造函数”/“子类”,那么将类型层次结构模拟为 ADT 是很困难的。

2. ADT 一词永远不适用于 Scala 代码,因为 Scala 在该语言中缺少 ADT。但是,您提供的类的行为类似于 ADT,所以我会说“足够接近”。

3 & 4.语言有不同的长处和短处。

Haskell 可以模拟每个 Scala 语言功能,Scala 可以模拟每个 Haskell 功能,因为这两种语言都是图灵完备的,并且允许不同级别的元编程。Haskell 当然有 Template Haskell,它允许模拟任何东西——您可能使用 TH 能够在 Haskell 文件中编写 Scala 代码并将其编译为 Haskell。

Haskell 中不需要对象和继承,Scala 中大多不需要 ADT,因此没有理由将两者进行比较。大多数面向对象的特性也可以用简单的 Haskell 类型类和数据类型以及使用模块边界来模拟。ADT 可以在 Scala 中用案例类来模拟,而 Haskell 类型的类可以用隐式参数和隐式对象实例来模拟。

但是,我想说的是,在 Haskell 中模拟某些 Scala 功能通常更容易,因为 Haskell 允许比 Scala 更多的“隐式语言扩展”。我的意思是,如果你想Monad在 Scala 中模拟 Haskell s,你必须在使用 s 的部分编写大量代码Monad,而如果你想模拟,比如说,Scala 的定界延续或 Haskell 中的隐式参数, 你可以简单地写一个Monad实例(用于延续)或多参数类型类(用于隐式参数)一次,您稍后在实际函数中编写的代码看起来非常接近 Scala 代码,没有太多样板。Scala 的许多高级功能(如果不是大部分的话)也确实源自 Haskell 或 OCaml,因此它们已经存在并且不需要翻译。

换句话说:添加新功能所需的复杂代码只需在 Haskell 中的一个位置添加,之后它可以很容易地在多个位置使用,而您通常必须在您的任何地方添加大量“噪音”如果您想模拟 Haskell 功能,请使用 Scala 代码。

于 2012-08-21T14:47:55.497 回答
5

您可以在 Haskell 中模仿 Scala 设计,尽管 Haskell 鼓励使用限定类型和求和类型而不是 Scala 的继承和子类型。摆脱我对 Scala 的有限知识,我在下面的 Haskell 中写了同样的东西。

  • 特征是类
  • 案例类是 ADT
  • 特征继承是类成员
  • 特征类型成员是有界存在类型
  • Typeable用于向下转换
-- Define traits
class Typeable a => Sql a
class (Typeable a, Sql a) => Statement a
class (Typeable a, Sql a) => Where a

-- Define case classes
data Union  where Union     :: (Statement a, Statement b) => a -> b -> Union deriving (Typeable)
data Select where Select    :: Where a => a -> Select                        deriving (Typeable)          

data And    where And       :: (Where a, Where b) => a -> b -> And           deriving (Typeable)
data Or     where Or        :: (Where a, Where b) => a -> b -> Or            deriving (Typeable)
data Equals where Equals    :: Equals                                        deriving (Typeable)

-- Define subtyping
instance Sql Union
instance Statement Union
instance Sql Select
instance Statement Select
instance Sql And
instance Where And
instance Sql Or
instance Where Or
instance Sql Equals
instance Where Equals

在 Haskell 中,您可能会使用 sum 类型而不是StatementandWhere类。

class Sql a
instance Sql Statement
instance Sql Where

data Statement = Union Statement Statement | Select Where
data Where = And Where Where | Or Where Where | Equals
于 2012-08-21T14:55:05.063 回答
0

问题 4 的一种可能答案:

Haskell 的类型推断(Hindley-Milner)在存在继承时会出现问题,因此 Scala 具有继承,但类型推断器的功能较弱。

于 2014-03-30T00:18:10.273 回答