繁体   English   中英

Scala和Haskell中的“复合”代数数据类型

[英]“Composite” algebraic data types in Scala and Haskell

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

  1. 我是否可以用Haskell表示具有“子类型” Statement具有构造函数Select的模型,例如Sql类型的模型? (似乎可能是相关的)。
  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

不可以因为你根本特点是密封的,有可能代表所提出的层次结构的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当然具有模板Haskell,该模板允许进行任何模拟-您可能使用TH能够在Haskell文件中编写Scala代码并将其编译为Haskell。

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

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

换句话说:添加新功能所需的复杂代码仅需在Haskell的一个位置添加,此后即可在多个位置轻松使用,而您通常必须在各处各处添加大量“噪声”如果要模拟Haskell功能,请使用Scala代码。

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

  • 性格是阶级
  • 案例类别是ADT
  • 性状继承是阶级成员
  • 特质类型的成员是有界的存在性类型
  • Class 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中,您可能会使用求和类型而不是StatementWhere类。

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

问题4的一种可能答案:

Haskell的类型推断(Hindley-Milner)在存在继承的情况下会遇到问题,因此Scala具有继承但功能较弱的类型推断器。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM