2012-12-29 81 views
1

免责声明:这是家庭作业的一部分。 我想实现自定义列表对象的flatMap。我已经成功实现了地图,但是我对flatMap有问题。我不知道如何将我从地图中获得的列表变平。我不知道我是否真的应该使用地图。实施flatMap功能

trait List[+A] { 
    /** The first element */ 
    def head: A 
    /** The rest of the elements */ 
    def tail: List[A] 
    def flatMap[B](f: A => List[B]): List[B] 
    def map[B](f: A => B): List[B] 

    // Concatenate two lists 
    def concat[B >: A](that: List[B]): List[B] = this match { 
    case Empty => that 
    case NonEmpty(head, tail) => NonEmpty(head, tail concat that) 
    } 
} 

case object Empty extends List[Nothing] { 
    def head = throw new UnsupportedOperationException("Empty.head") 
    def tail = throw new UnsupportedOperationException("Empty.tail") 
    def flatMap[B](f: Nothing => List[B]): List[B] = Empty 
    def map[B](f: Nothing => B): List[B] = Empty 

    override def toString = "Empty" 
} 

case class NonEmpty[A](head: A, tail: List[A]) extends List[A] { 

    def map[B](f: A => B): List[B] = { 

    NonEmpty(f(head), tail.map(f)) 

    } 
def flatMap[B](f: A => List[B]): List[B] = { 
    val a = this.map(f) 
    for (x <- a; y <- x) yield y 
    } 
} 
+0

+1免责声明。 SO应该有一个标签,或者他们可以。 –

+0

他们确实有它,但它说它已被弃用 – LearnToMath

回答

2

的你必须写flatMap为长度为n的列表。试着解决它,假设你已经解决了它的长度为n-1的列表。如果你能做到这一点,那么你解决了这个问题,因为n => n-1 => ... => 1 => 0,并且对于0你已经有了一个解决方案。

这种思维适合你的List,因为它是一个递归类型。

你已经用map完成了这个,用flatMap也一样。这两个函数都是从List [A]到List [B]的转换,唯一的区别是它们可以使用的工具,map有一个将A转换为B的函数,而flatMap具有将A转换为List [B]

+0

f(head)concat tail.flatMap(f)是否正确? – LearnToMath

+0

是的,那也是我想带你去的;-) – drexin

3

因为这是一项功课,我不想给你一个完整的解决方案,只是一些提示。

  1. 你不需要map实现flatMap(实际上很容易做到这一点的其他方式),你有你需要的一切(flatMap
  2. 需要返回一个List[B]List已经concat定义的函数)
  3. 实施第一EmptyflatMap的;-)
+0

我不小心未包含空列表的定义。我猜flatmap的定义也应该是递归的。如果函数应用于“typeof A”或List [A]上,我应该使用类似match 2 match 2的情况吗? – LearnToMath

+0

你是什么意思?你会得到一个函数,它接受列表中包含的任何类型,并返回另一个类型的新列表。为什么你需要匹配那里的东西? – drexin

+0

嗯,我不知道,我想如果我递归调用函数,我会不知何故需要区分它被调用的对象本身是一个列表(List [B])还是仅仅是一个B类型的对象 – LearnToMath