3

这是我的代码:

class Eapproximator
  var step : F64
  new create(step' :F64) =>
    step = step'

  fun evaluate() :F64 =>
    var total = F64(0)
    var value = F64(1)
    while total < 1 do
      total = total + step
      value = value + (value * step)
    end
    value

actor Main
  new create(env: Env) =>
    var e_approx = Eapproximator(0.00001)
    var e_val = e_approx.evaluate()
    env.out.print(e_val.string())

它运行良好并打印(如预期)2.7183。但是,如果我在定义中替换class为,我会得到一堆错误:actorEapproximator

Error:
/src/main/main.pony:18:34: receiver type is not a subtype of target type
    var e_val = e_approx.evaluate()
                                 ^
    Info:
    /src/main/main.pony:18:17: receiver type: Eapproximator tag
        var e_val = e_approx.evaluate()
                    ^

    /src/main/main.pony:6:3: target type: Eapproximator box
      fun evaluate() :F64 =>
      ^
    /src/main/main.pony:3:3: Eapproximator tag is not a subtype of Eapproxim
ator box: tag is not a subcap of box
      new create(step' :F64) =>
      ^
Error:
/src/main/main.pony:19:19: cannot infer type of e_val

    env.out.print(e_val.string())

我能做些什么来解决这个问题?

4

1 回答 1

5

actor 是 Pony 中的并发单位。这意味着同一程序中的许多不同演员可以同时运行,包括你MainEapproximator演员。现在如果一个actor的字段被多个actor同时修改会发生什么?由于并发程序在现代硬件上的工作方式,您最终很可能会得到一些垃圾值。这被称为数据竞争,它是并发编程中许多很多错误的根源。Pony 的目标之一是在编译时检测数据竞争,此错误消息是编译器告诉您您尝试执行的操作可能不安全。

让我们来看看那个错误信息。

接收者类型不是目标类型的子类型

接收者类型是被调用对象的类型,e_approx这里。目标类型是this方法内部的类型,Eapproximator.evaluate这里。子类型意味着子类型的对象可以像超类型的对象一样使用。因此,该部分告诉您由于类型不匹配evaluate而无法调用。e_approx

接收器类型:Eapproximator 标签

e_approx是一个Eapproximator tag。一个tag对象既不能读也不能写。我会在一分钟内详细说明e_approx原因tag

目标类型:Eapproximator box

this里面evaluate是一个Eapproximator box. 一个box对象可以被读取,但不能被写入。thisbox因为evaluate被声明为fun evaluate,这隐含意味着fun box evaluate(这意味着默认情况下,方法不能修改它们的接收者。)

Eapproximator tag 不是 Eapproximator box 的子类型:tag is not a subcap of box

根据此错误消息,tag对象不是对象的子类型box,这意味着 atag不能像使用box. 如果我们看看什么tagbox允许,这是合乎逻辑的。box允许更多的东西tag:它可以读取,而tag不能。一个类型只能是另一个类型的子类型,如果它允许的东西比超类型少(或多)。

那么为什么classactormake 对象替换tag呢?这与我之前谈到的数据竞争问题有关。演员可以自由支配自己的领域。它可以读取它们并写入它们。由于参与者可以同时运行,因此必须拒绝他们访问彼此的字段,以避免与字段所有者发生数据竞争。类型系统中有一些东西可以做到这一点:tag. Actor 只能将其他 Actor 视为tag,因为读取或写入它们是不安全的。它可以对这些tag引用做的主要有用的事情是发送异步消息(通过调用be方法或行为),因为这既不是读取也不是写入。

当然,由于你没有Eapproximator在你的程序中做任何突变,你的具体情况是安全的。但是尝试禁止每个不安全的程序比尝试允许除此之外的每个安全程序要容易得多。

总而言之,除了Eapproximator作为一个类保留之外,您的程序并没有真正的修复。没有任何东西需要成为 Pony 程序中的演员。演员是并发的单位,但这意味着它也是顺序的单位。需要顺序和同步的计算必须存在于单个参与者中。然后,您可以将这些计算分解为不同的类,以获得良好的代码卫生。

于 2017-12-28T03:24:36.330 回答