2012-12-29 84 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