coursera作业之(集合)函数对象

本文分享了使用Scala实现纯函数式Set的过程,重点介绍了map和exists函数的难点及解决方案,利用数学集合运算来理解并解决编程问题。

第二次作业


这次作业做了大约两小时,大部分时间是花在了map和exists上
其中map,我一开始的答案是
  def map(s: Set, f: Int => Int): Set = {
    x=>s(f(x)) // ERROR
  }
但是这样的话,因果关系就反掉了,假如s = {9}, f: x=>x/3
那么最终的返回值其实是x=>s(x/3),也就是x/3要在s这个Set里存在,也就是说,返回值是{27}
所以最后仍然用了遍历,每当有和x/3相等的值时,就加入集合,最后返回这个集合

exists
挺难的,而且我觉得,就正如题目的Hint所说:
this assignment needs more thinking (whiteboard, pen and paper) than coding ;-). 
因为这道exists其实不是考察编程能力,而是分析能力
我最后的思路是想到了数学中的集合运算,因为题目的要求是exists必须用到forall函数,可是我实在想不出有什么原因要用到它
后来把思路拓展到数学集合运算,发现forall(x,y)其实就是判断前者x是否是后者y的子集
而exists就是算出两个集合有没有非空公共子集,但是有个问题:空集是任何集合的子集,不能直接用interfact
最后苦思冥想想到:
exists 等价于 两个集合x,y有非空公共子集,等价于两个集合x,y没有非空公共子集的取反,等价于x集合取反是y的子集 逻辑与 && y集合取反是x的子集
但是一个集合的取反要靠辅助函数构造一个全集,然后diff(全集,某个集合) 实现,于是最后代码如下:
!(forall(s, diff(ful, p)) && forall(p, diff( ful, s)))

https://class.coursera.org/progfun-003/assignment/view?assignment_id=3

package funsets

import common._

/**
 * 2. Purely Functional Sets.
 */
object FunSets {
  /**
   * We represent a set by its characteristic function, i.e.
   * its `contains` predicate.
   */
  type Set = Int => Boolean

  /**
   * Indicates whether a set contains a given element.
   */
  def contains(s: Set, elem: Int): Boolean = s(elem)

  /**
   * Returns the set of the one given element.
   */
  def singletonSet(elem: Int): Set = {
    x: Int => x == elem
  }

  /**
   * Returns the union of the two given sets,
   * the sets of all elements that are in either `s` or `t`.
   */
  def union(s: Set, t: Set): Set = {
    x: Int => s(x) || t(x)
  }

  /**
   * Returns the intersection of the two given sets,
   * the set of all elements that are both in `s` and `t`.
   */
  def intersect(s: Set, t: Set): Set = {
    x: Int => s(x) && t(x)
  }

  /**
   * Returns the difference of the two given sets,
   * the set of all elements of `s` that are not in `t`.
   */
  def diff(s: Set, t: Set): Set = {
    x: Int => s(x) && !t(x)
  }

  /**
   * Returns the subset of `s` for which `p` holds.
   */
  def filter(s: Set, p: Int => Boolean): Set = {
    x: Int => s(x) && p(x)
  }

  /**
   * The bounds for ` forall` and `exists` are +/- 1000.
   */
  val bound = 1000

  /**
   * Returns whether all bounded integers within `s` satisfy `p`.
   */
  def forall(s: Set, p: Int => Boolean): Boolean = {
    /**
     * 1. Consider  p: Int => Boolean  as a Set
     * 2. Consider function as an object
     */
    def iter(a: Int): Boolean = {
      if (a > bound) true
      else if (s(a) && !p(a)) false
      else iter(a + 1)
    }
    iter(-bound)
  }

  /**
   * Returns whether there exists a bounded integer within `s`
   * that satisfies `p`.
   */
  def exists(s: Set, p: Int => Boolean): Boolean = {
    def iter(a: Int, set: Set): Set = {
      if (a > bound) set
      else iter(a + 1, union(set, singletonSet(a)))
    }
    val ful = iter(- bound, Set())
    !(forall(s, diff(ful, p)) && forall(p, diff( ful, s)))
  }

  /**
   * Returns a set transformed by applying `f` to each element of `s`.
   */
  def map(s: Set, f: Int => Int): Set = {
    def iter(a: Int, set: Set): Set = {
      if (a > bound) set
      else if (s(a)) iter(a + 1 , union(set, singletonSet(f(a))))
      else iter(a + 1, set)
    }
    iter(-bound, Set())
    // x=>s(f(x)) // ERROR
  }

  /**
   * Displays the contents of a set
   */
  def toString(s: Set): String = {
    val xs = for ( i <- -bound to bound if contains(s, i)) yield i
    xs.mkString( "{", "," , "}" )
  }

  /**
   * Prints the contents of a set on the console.
   */
  def printSet(s: Set) {
    println(toString(s))
  }
}

new TestSets {
  val r = union(s1, s3)
  val s = union(s1, s2)
  val t = union(s1, s2)
  assert(forall(s, t), "forall 1")
  assert(!forall(s, r), "forall 2")

  assert(exists(s, r), "exists 1")

  val sMap = singletonSet( 9)
  assert(exists(map(sMap, x => x / 3), s3), "exists 2")
  assert(exists(s1, s1), "exists 3")
  assert(!exists(s2, r), "exists 4")
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值