【问题标题】:Functional Programming scala函数式编程
【发布时间】:2017-06-18 22:06:18
【问题描述】:

我在学习 coursera 上的“Scala 中的函数式编程原则”,第二周的作业是关于“纯函数集”的 我们有,

type Set = Int => Boolean

然后是一些功能,如

def union(s: Set, t: Set): Set = (element: Int) => s(element) || t(element)

所以,当我这样做时,

val u = union(Set(1, 2, 3), Set(4, 5, 6))

在 scala 控制台中,它给出了

u: Set = <\function1\>

a)为什么会返回一个函数?

b) 当我执行 contains(u, 6) 时,它返回 true,但我可以显示 u 中的所有元素还是因为 u 是我不能显示的函数?

c)union(Set(1, 2, 3), Set(4, 5, 6)) 如何在不进行任何迭代的情况下返回这两组中的所有元素?

【问题讨论】:

    标签: scala functional-programming higher-order-functions


    【解决方案1】:

    a) 为什么它返回一个函数?

    因为Set 是一个函数。 Int =&gt; Boolean 表示“一个函数采用 Int 并返回 Boolean。”

    b) 当我执行contains(u,6) 时,它返回 true,但我可以显示 u 中的所有元素还是因为 u 是我不能显示的函数?

    您无法显示所有元素,因为 Set 实际上并不“包含”元素。 Set 是一个或多个返回真/假的测试的函数。

    c) union(Set(1,2,3),Set(4,5,6)) 如何在不进行任何迭代的情况下返回这两个集合中的所有元素?

    了解给定Set 中哪些值返回 true 的唯一方法是传入所有可能的值(或一些可接受的近似值)。 Set 中的值将返回 true 否则您将得到 false

    注意:这仅适用于问题中定义的Set。 Scala 标准库中的 Set 是另一种动物。

    【讨论】:

    • Set如何同时是数据结构和函数?
    • 这可能取决于您如何定义“数据结构”。有人可能会争辩说,Set 函数 是一种 的数据结构,仅仅是因为它的行为就像一个数据结构,但大多数人希望数据结构在它包含的每个元素和函数Set 不这样做。这是所有负整数的Setval neg:Set=_&lt;0 正如我所提到的,标准库Set 是不同的。那是一个正确的数据结构。 Coursera Set 旨在帮助学生习惯于以“一等公民”的身份处理功能,即像数据一样传递。
    【解决方案2】:

    毫无疑问,这是一件复杂的事情。让我们看看情况如何。
    现在我这样做了:

      type Sett = Int => Boolean
    
      def union(s: Sett, t: Sett): Sett = 
        (element: Int) => s(element) || t(element)
    
      val x = Set(1, 2, 3).asInstanceOf[Sett]
      val y = Set(4, 5, 6).asInstanceOf[Sett]
      val u = union(x, y)
    
      def contains(s: Sett, elem: Int): Boolean = s(elem)
    
      println(contains(u, 6))
    

    注意我正在使用 Sett!未设置。上面的Set其实就是scala.collections.immutable.Set。 Sett 是我自己的自定义“类型”。该类型定义为 Int => Boolean ,即以 Int 作为参数并返回布尔值的函数类型。我将自定义类型重命名为 Sett 以避免混淆一个是我的类型,而另一个属于 Scala 库。
    我在上面的代码中强调的另一件事是,我将 Scala 的 Set 转换为我的 Sett!这个演员阵容有效!它是如何工作的?这是因为不可变 Set 继承自 Function1.. 所以效果很好.. 此评论感谢下面的 Jorge
    Scala Set 实际上是 Set[Int],因为它是 Set(1,2,3) 等。因此将它转换为符合 Int => Boolean 的子类 Sett 是完全合法的。做吧

    val x = Set(1,2,3)
    println(x(2))
    println(x(4))
    

    因此它证明了 Scala 的 Set 在签名上与 Sett 的这一操作兼容。
    不需要联合中的迭代。 Sett 类型持有对两个集合的引用。 如果你这样做:

      def union(s: Sett, t: Sett): Sett =
        (element: Int) => {
          println(element)
          s(element) || t(element)
        }
    
    val u=union(Set(1,2,3),Set(4,5,6)) 
    

    .. 然后你调用 u(2) 或其他什么,联合 def 被调用,参数 element=2。然后调用“s(element) || t(element)”。集合操作是 1 阶的,即恒定时间。 s(element) 操作不需要迭代,因为 Set 基本上是不使用值部分的 Map。仅使用键,并且键是唯一的。
    Martin Odersky 真的在这里过激,走得太远了。应该更慢。涵盖的概念太多。

    【讨论】:

    • 这里没有鸭子打字。 scala.collection.immutable.Set[Int]继承自Int ⇒ Boolean,而Sett只是Int ⇒ Boolean的类型别名,所以SetSett的子类,将子类类型的实例强制转换为超类类型的实例。
    • pedofurla 可能会变得更有建设性并提供您宝贵的意见。问题是......是......你不能
    • 有趣的是,你没有问“你是如何错过练习的重点的”。现在,即使你问,你也不会得到我的回答。
    • 好吧,如果你问得好的话。
    • 先生 pedrofurla 为我的言论道歉。我相信你看到的东西比我所能看到的要多,并且承认你知道的东西比我知道的要多。请分享你的知识。我将非常感谢先生。谢谢。