【问题标题】:Side effects in ScalaScala 中的副作用
【发布时间】:2012-07-22 03:40:22
【问题描述】:

这些天我正在学习 Scala。我对 Haskell 有点熟悉,虽然我不能声称自己很了解。

对Haskell不熟悉的人的补充说明

我喜欢 Haskell 的一个特点是,不仅函数是一等公民,副作用(让我称之为动作)也是一等公民。执行时将赋予您a 类型值的操作属于特定类型IO a。您可以像传递任何其他值一样传递这些操作,并以有趣的方式将它们组合起来。

事实上,结合副作用是 Haskell 中对它们做某事的唯一方法,因为你无法执行它们。相反,执行的程序是由main 函数返回的组合操作。这是一个巧妙的技巧,它可以让函数成为纯函数,同时让您的程序实际做一些事情而不是消耗能量。

这种方法的主要优点是编译器知道您执行副作用的代码部分,因此它可以帮助您捕获错误。

实际问题

在 Scala 中是否有某种方法可以让编译器类型为您检查副作用,例如,保证您不会在某个函数内执行副作用?

【问题讨论】:

  • 一段时间以来,我一直在以公开的书面形式和我自己的想法发表附文。但我不知道他们的名字。不经意间,你教育了我。 #upvoting

标签: scala functional-programming monads side-effects purely-functional


【解决方案1】:

强制引用透明性的能力与 Scala 拥有与 Java 可互操作的类/对象系统的目标非常不兼容。

Java 代码可以以任意方式不纯(并且在 Scala 编译器运行时可能无法用于分析),因此 Scala 编译器必须假设 所有 外来代码是不纯的(为它们分配 @ 987654321@ 类型)。要使用对 Java 的调用来实现纯 Scala 代码,您必须将调用包装在与 unsafePerformIO 等效的内容中。这增加了样板,使互操作性变得不那么愉快,但它变得更糟。

必须假设所有 Java 代码都在 IO 中,除非程序员另有承诺,否则几乎会扼杀从 Java 类的继承。所有继承的方法都必须假定为IO 类型;这甚至适用于接口,因为 Scala 编译器必须假设在 Java 领域的某个地方存在不纯的实现。因此,您永远不能从 Java 类或接口派生具有任何非IO 方法的 Scala 类。

更糟糕的是,即使是在 Scala 中定义的类,理论上也可能存在一个在 Java 中定义的带有不纯方法的未跟踪子类,其实例可能会作为父类的实例传回 Scala。因此,除非 Scala 编译器能够证明给定对象不可能是由 Java 代码定义的类的实例,否则它必须假定对该对象的任何方法调用都可能调用由Java 编译器不遵守返回不在IO 中的结果的函数的规则。这将迫使几乎所有内容都在IO 中。但是将所有内容都放入IO 完全等同于在IO 中不放入任何内容,只是不跟踪副作用!

所以最终,Scala 鼓励你编写纯代码,但它并没有试图强制你这样做。就编译器而言,任何对任何东西的调用都会产生副作用。

【讨论】:

  • 这是一个很好的答案,但为有趣的链接接受了唐的答案
【解决方案2】:

不,这在 Scala 中原则上是不可能的,因为该语言不强制引用透明性——语言语义忽略了副作用。您的编译器不会为您跟踪和强制消除副作用。

您将能够使用tag some actions 的类型系统作为IO 类型,但是通过程序员的纪律,获得一些编译器支持,但没有编译器证明。

【讨论】:

  • 谢谢,你链接的帖子看起来很有趣!这正是我正在寻找的东西。
猜你喜欢
  • 2019-12-03
  • 2021-04-27
  • 1970-01-01
  • 1970-01-01
  • 2012-04-18
  • 2015-03-01
  • 1970-01-01
  • 2019-12-27
  • 2021-02-03
相关资源
最近更新 更多