- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我最近观看了一个关于如何提出 IO monad 的视频,演讲是用 scala 进行的。我实际上想知道让函数返回 IO[A] 的意义何在。包装在 IO 对象中的 lambda 表达式就是突变,在更高的某个时刻,它们必须被观察到,我的意思是执行,以便发生一些事情。您不只是将问题推到更高的位置吗?
我能看到的唯一好处是它允许延迟计算,从某种意义上说,如果您不调用 unsafePerformIO 操作,则不会发生副作用。另外我猜想程序的其他部分可以使用/共享代码并决定何时发生副作用。
我想知道这就是全部吗?在可测试性方面有什么优势吗?我假设不是,因为你必须观察抵消这一点的影响。如果您使用特征/接口(interface),您可以控制依赖关系,但当这些依赖关系发生影响时则无法控制。
我将以下示例放在代码中。
case class IO[+A](val ra: () => A){
def unsafePerformIO() : A = ra();
def map[B](f: A => B) : IO[B] = IO[B]( () => f(unsafePerformIO()))
def flatMap[B](f: A => IO[B]) : IO[B] = {
IO( () => f(ra()).unsafePerformIO())
}
}
case class Person(age: Int, name: String)
object Runner {
def getOlderPerson(p1: Person,p2:Person) : Person =
if(p1.age > p2.age)
p1
else
p2
def printOlder(p1: Person, p2: Person): IO[Unit] = {
IO( () => println(getOlderPerson(p1,p2)) ).map( x => println("Next") )
}
def printPerson(p:Person) = IO(() => {
println(p)
p
})
def main(args: Array[String]): Unit = {
val result = printPerson(Person(31,"Blair")).flatMap(a => printPerson(Person(23,"Tom"))
.flatMap(b => printOlder(a,b)))
result.unsafePerformIO()
}
}
你可以看到效果是如何推迟到 main 的,我认为这很酷。我是从视频中感受到这一点后想到的。
我的实现是否正确以及我的理解是否正确。
我还想知道是否应该将里程与 ValidationMonad 结合起来,如 ValidationMonad[IO[Person]] 中那样,以便在发生异常时可以短路?请思考。
布莱尔
最佳答案
函数的类型签名对于记录它是否有副作用是很有值(value)的。您的 IO 实现很有值(value),因为它确实完成了这么多工作。它使您的代码得到更好的记录;如果您重构代码以尽可能地将涉及 IO 的逻辑与不涉及 IO 的逻辑分开,那么您就使不涉及 IO 的函数变得更可组合且更可测试。您可以在没有显式 IO 类型的情况下进行相同的重构;但使用显式类型意味着编译器可以帮助您进行分离。
但这只是开始。在您问题的代码中,IO 操作被编码为 lambda,因此是不透明的;除了运行 IO 操作之外,您无法对它执行任何操作,并且运行时的效果是硬编码的。
这不是实现 IO monad 的唯一可能方法。
例如,我可能会创建扩展共同特征的 IO 操作案例类。例如,然后我可以编写一个测试来运行一个函数并查看它是否返回正确的 IO 操作种类。
在这些代表不同类型 IO 操作的类的情况下,我可能不会包含这些操作在运行时执行的操作的硬编码实现。相反,我可以使用类型类模式将其解耦。这将允许交换 IO 操作的不同实现。例如,我可能有一组与生产数据库通信的实现,以及另一组与模拟内存数据库通信以用于测试目的的实现。
Bjarnason 和 Chiusano 的《Scala 函数式编程》一书的第 13 章(“外部效果和 I/O”)对这些问题进行了很好的处理。特别参见第 13.2.2 节“简单 IO 类型的优点和缺点”。
更新:关于“交换 IO 操作的不同实现”,您可能会查找“free monad”,这是一种安排方法。同样相关的是“无标记最终”风格,在这种风格中,您可以独立于具体类型(例如 IO
)编写单子(monad)代码。
关于Scala IO 单子(monad) : what's the point?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19687470/
为什么这不返回每个社区(边界框)中的点数? import geopandas as gpd def radius(points_neighbour, points_center, new_field_
嘿! 我有一张图片,我想在该图片上选择一个点并告诉它应该变换到哪个坐标。我想为一些数字点做这个。当我完成时,整个图像会发生变化,因此会考虑局部性。 最重要的是,我可以选择任意多的点,并且所选的点会转换
我有代码: class Point3D{ protected: float x; float y; float z; public:
我正在开发我的第一个 Spring Boot + Spring Data JPA + Hibernate 5,在 PostgreSQL 上工作数据库。 我在尝试映射具有 point 作为数据类型的字段
当我尝试编译这个简单的代码时,我在构造函数中遇到了两个错误:“类型值不能用作默认参数”我该如何解决这个问题? public class PointerArgs { public P
当我尝试编译这个简单的代码时,我在构造函数中遇到了两个错误:“类型值不能用作默认参数”我该如何解决这个问题? public class PointerArgs { public P
目前我正在实现一项提供集体旅行的交通服务,但我遇到了一个问题: 假设我在下图中得到了点 G = {A,B,C,D,F,R,W} =>。 当用户选择 from(A) -> to(W) 时,它们之间有点:
我有一个名为 Shop 的实体,它有一个名为 Position 的 DBGeorgpraphy 列 数据库中的示例商店的位置值为 POINT (145.034242 -37.825519) 我正在尝试
我看了几个类似的帖子,但我要么不明白他们提供的是什么,要么他们似乎不适用。我是新来的,我会尽力遵守规则。 我们在类(class)的最后 2 周学习 c++,期末学习 40 小时 :),所以我是初学者。
我正在使用 tf2 将点从源帧转换为目标帧。下面是代码片段: import tf2_ros import tf2_geometry_msgs transform = tf_buffer.lookup_
我需要找到一种算法,根据给定的一组大小为 n 的点 S 计算凸包。我知道 S 正好有 6 个点 构成了凸包。 最好和最有效的方法是什么? 我想从 S 生成所有可能的点组合(这将是 n 选择 6 个点)
我有一个在屏幕坐标中的 CGPoint。我还有一个应用了变换矩阵(缩放、旋转和平移)的 CALayer。 如何将屏幕坐标中的点转换为图层的局部坐标? 最佳答案 CALayer 有执行此操作的方法,请在
我正在创建自定义控件,它将从点列表(或数组)中绘制形状。我已经完成了基本的绘图功能,但现在我正在为 Visual Studio 中的设计时支持而苦苦挣扎。 我创建了两个属性: private Poin
此函数是从“JavaScript:权威指南”复制的,但由于某种原因它不起作用... **points.dist = function () { ^ ReferenceError: 点未定义**我对此很
我有一个像这样的自定义适配器: private List items = new ArrayList<>(); private Context context; public UserSpinnerA
代码: UPDATE tbl_name SET points = points + 1 WHERE 'GAME 1' LIKE "%Vikes%" GAME 1 列包含包含 Vikes
我有一个点。我正在尝试将 x 作为 int。如果我使用 Point.x,我将得到 x 作为 int。但我的印象是我应该尽可能使用 setter/getter ( Why use getters and
我正在开发一个小型信誉系统,但遇到了一个问题。 因此,在我的示例中,我想为 4 种不同类型的用户创建一个图片网站;我们称他们为:业余、好、非常好、专业。 每个用户可以上传一张图片,这张图片可以被其他用
我有一个关于事件形状模型的问题。我正在使用 T. Coots 的论文(可以找到 here 。) 我已经完成了所有初始步骤(Procrustes 分析计算平均形状,PCA 减少尺寸)但仍停留在拟合上。
Android moving Image one point (0,0) to another point (30,400). using animation or normal looping co
我是一名优秀的程序员,十分优秀!