首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >书中Scala 3“模块抽象”一章

书中Scala 3“模块抽象”一章
EN

Stack Overflow用户
提问于 2022-08-29 16:09:31
回答 1查看 40关注 0票数 1

我正在尝试使用“不透明类型”一章中的第二种方法(“模块抽象”)。代码旨在展示如何使Scala使用对数数字表示。

问题是,我不知道如何使用书中的代码。对我来说,这是行不通的。

代码语言:javascript
复制
trait Logarithms:

  type Logarithm

  // operations on Logarithm
  def add(x: Logarithm, y: Logarithm): Logarithm
  def mul(x: Logarithm, y: Logarithm): Logarithm

  // functions to convert between Double and Logarithm
  def make(d: Double): Logarithm
  def extract(x: Logarithm): Double

  // extension methods to use `add` and `mul` as "methods" on Logarithm
  extension (x: Logarithm)
    def toDouble: Double = extract(x)
    def + (y: Logarithm): Logarithm = add(x, y)
    def * (y: Logarithm): Logarithm = mul(x, y)
    // I added
    def myToDouble: Double = extract(x)


object LogarithmsImpl extends Logarithms:

  type Logarithm = Double

  // operations on Logarithm
  def add(x: Logarithm, y: Logarithm): Logarithm = make(x.toDouble + y.toDouble)
  def mul(x: Logarithm, y: Logarithm): Logarithm = x + y

  // functions to convert between Double and Logarithm
  def make(d: Double): Logarithm = math.log(d)
  def extract(x: Logarithm): Double = math.exp(x) 

// I added
object Logarithms:
  def apply(d: Double) = LogarithmsImpl.make(d)

书上说:

然而,这种抽象有点漏洞百出。我们必须确保只对抽象接口Logarithms进行编程,而不直接使用LogarithmsImpl。直接使用LogarithmsImpl将使等式Logarithm = Double对用户来说是可见的,用户可能会意外地使用一个预期为对数双倍的Double

现在我试着用它:

代码语言:javascript
复制
$ ~/Downloads/scala3-3.1.3/bin/scala
Welcome to Scala 3.1.3 (14.0.1, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
                                                                                                                           
scala> :load my/scala/logarithms1.scala
// defined trait Logarithms
// defined object LogarithmsImpl
// defined object Logarithms
                                                                                                                           
scala> import Logarithms.*
                                                                                                                           
scala> Logarithms(4)
val res0: LogarithmsImpl.Logarithm = 1.3862943611198906
                                                                                                                           
scala> Logarithms(2)
val res1: LogarithmsImpl.Logarithm = 0.6931471805599453
                                                                                                                           
scala> Logarithms(4).toDouble
val res2: Double = 1.3862943611198906
                                                                                                                           
scala> Logarithms(4).myToDouble
-- [E008] Not Found Error: ----------------------------------------------------------------------------------------------------
1 |Logarithms(4).myToDouble
  |^^^^^^^^^^^^^^^^^^^^^^^^
  |value myToDouble is not a member of LogarithmsImpl.Logarithm, but could be made available as an extension method.
  |
  |The following import might fix the problem:
  |
  |  import LogarithmsImpl.myToDouble
  |
1 error found

实际上,导入LogarithmsImpl并没有多大帮助:

代码语言:javascript
复制
scala> import LogarithmsImpl.*
                                                                                                                           
scala> import Logarithms.*
                                                                                                                           
scala> val ll: Logarithm = make(4.0)
val ll: LogarithmsImpl.Logarithm = 1.3862943611198906
                                                                                                                           
scala> val lll: Logarithm = make(2.0)
val lll: LogarithmsImpl.Logarithm = 0.6931471805599453
                                                                                                                           
scala> lll+ll
val res0: Double = 2.0794415416798357
                                                                                                                           
scala> extract(lll+ll)
val res1: Double = 7.999999999999998

最后一行显示加法是传统的浮点加法,而不是扩展中的覆盖。

,我错过了什么?

UPD本书代码中的另一个问题:行

代码语言:javascript
复制
  def add(x: Logarithm, y: Logarithm): Logarithm = make(x.toDouble + y.toDouble)

应该是

代码语言:javascript
复制
  def add(x: Logarithm, y: Logarithm): Logarithm = make(x.myToDouble + y.myToDouble)

或者更好的是:

代码语言:javascript
复制
  def add(x: Logarithm, y: Logarithm): Logarithm =  x + math.log1p(math.exp(y-x))

UPD2,它看起来像特征和对象不是同伴,一个特征不是一个类,只有类可能是同伴。

EN

回答 1

Stack Overflow用户

发布于 2022-08-29 16:46:55

使用此抽象(我可以看到)的最合理方法如下:

代码语言:javascript
复制
@main
def main = {
  val L = LogarithmsImpl
  doStuffWithLogarithm(L)
}

def doStuffWithLogarithm(L: Logarithms): Double = {
  import L.*
  val a = L.make(1)
  val b = L.make(2)
  a.myToDouble
}

它的要点是,您必须传递一些Logarithms实例,并使用它访问所有方法,这样类型别名等式就不会泄漏。

恐慌:https://scastie.scala-lang.org/KacperFKorban/4bnxghkMSzaPqn4vvy19QA/1

这就是为什么这不是一个很好的模式。以及为什么opaque types有用。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73531615

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档