2010-01-28 36 views
1

我可以實現與val一個def其中def不帶任何參數:實現帶有N個參數類型的VAL一個高清功能N

trait T { def foo: Int } 
class C(val foo: Int) extends T 

爲什麼能不擴展到實施def以n ARGS到val這是一個FunctionN?我想有可能實現這樣的:

def expensiveOperation(p: Int => Boolean) : List[Int] 

有了一個懶惰的功能val。例如:

val expensiveOperation = { 
    val l = //get expensive list 
    l.filter _ //partially applied function 
} 

我知道這個語法在2.8上似乎不起作用。是否有什麼我失蹤了,爲什麼我不能實現一個def以參數作爲功能val

+0

我很困惑。你的val看起來像一個'Function0',而不是'Function1'。它應該採取什麼參數?此外,val中沒有短路,所以你爲什麼要這麼做?如果發生短路,爲什麼不使用'Stream'而不是'List'? – 2010-01-28 15:02:50

+0

我不明白這個問題。你能更清楚地解釋你想做什麼,而不是你如何去做。目前你只告訴我們「如何」部分。 – 2010-01-28 15:03:46

+0

我的'val'是一個函數1,因爲它本質上是一個指向'List.filter'方法的指針(它將'Function1'作爲參數。我的問題是,我可以有一個'val'實現一個'def',其中'def'不需要任何參數,但是我不明白爲什麼不能用args擴展到'def's? – 2010-01-28 15:45:33

回答

2

現在,後期編輯,我想我明白你是什麼之後。但是你不能做你想做的事,因爲類型簽名不匹配。

def x: Int = 5 
val x: Int = 5 

在這兩種情況下你都不提供任何東西並取回一個Int(在本例中爲5)。大!

def expensive(p: Int => Boolean): List[Int] 

現在你提供一些東西。但是val只是某個地方的存儲對象。您可以將提供給標籤引用的對象,但這不同於向標籤'x'提供某些東西。

下面是你需要的,如果你想有一個VAL覆蓋它使用DEF:

def expensive: (Int=>Boolean)=>List[Int] 

現在你有,你不帶參數調用的東西,它返回的東西,可以採取INT =>布爾函數並給你一個List [Int]作爲回報。這正是你用val得到的結果 - 在這兩種情況下,你都有一個返回具有所需功能的對象的名稱。

(在Scala中,丘壑實際上與不帶參數,並在隱藏字段返回任何的getter方法隱藏字段來實現。所以,它真的是就像高清是一個方法。)

+0

時,它不是一個「漂亮」的解決方案,而只是保存列表並調用'filter',但是我可以通過一個'def'來實現'def',它需要參數?答案當然是堅定的「不」!我得到你的論點,這在細節上無疑是正確的,但是這兩個項目*應該是相等的。我預見的唯一合乎邏輯的問題是可變性。即'可變參數' – 2010-01-28 17:59:53

+0

它們在邏輯上是等價的,假設(1)除了調用它的應用之外,你對返回的對象沒有做任何事情,(2)你不關心實現細節(例如可能與性能有關的)你不在乎有一個額外的間接水平。這可能是一個說法,即編譯器應該將每個方法轉換爲一個函數,或者你失去了一個val的普通getter,它會覆蓋具有參數的def並將其替換爲也調用apply的專用getter(並因此符合類型簽名的def)。 – 2010-01-28 18:11:06

0

編輯:沒關係,我也沒弄清楚你實際上意味着。但是如果你的意思我以爲......

您可以使用縮寫語法,創建適用的操作的VAL:

val expensive = (p: (Int) => Boolean) => { 
    val l = List(1,2,3,4) 
    l filter p 
} 
scala> expensive(_<3) 
res1: List[Int] = List(1,2) 

但這實際上並沒有緩存列表,這是什麼我想你想要。原因在於,這個簡短的語法將=>之後的所有內容放入Function1的apply方法中。你可能想在列表存儲像這樣:

val expensive = new Function1[Int=>Boolean,List[Int]] { 
    lazy val l = List(1,2,3,4) 
    def apply(p: (Int) => Boolean) = { l filter p } 
} 

和不存在很大的速記,我知道的。

編輯:如果你很高興該塊之外創建列表,然後有一個簡寫(見註釋也):

val expensive = List(1,2,3,4).filter _ 

scala> expensive(_ < 3) 
res6: List[Int] = List(1, 2) 
+0

但是,我給了'def'一個有效的*實現*嗎? – 2010-01-28 15:40:27

+0

(答案是** NO **) - 我可以通過聲明一個'val'來輕鬆地緩存我的昂貴操作 - 我的問題是關於這是一個'def'的實現,它不是 – 2010-01-28 15:43:47

+0

(沒關係,我剛剛看到你的編輯上面 - 這個評論不適用。) – 2010-01-28 16:40:56

1

你總是可以只將其轉發給您的VAL:

trait T { 
    def expensiveOperation(p: Int => Boolean) : List[Int] 
} 

class C extends T { 
    def expensiveOperation(p: Int => Boolean): List[Int] = { 
     expensiveOperationVal(p) 
    } 
    val expensiveOperationVal = { p: (Int=>Boolean) => 
    // ... lazy stuff 
    List(1,2,3) 
    } 
} 

而且,雖然這並不能回答你的問題,它看起來像除非你的// ... get expensive list代碼依賴於謂語p,那麼你可以只是做類似的東西:

class C extends T { 
    def expensiveOperation(p: Int => Boolean): List[Int] = { 
     myExpensiveList filter p 
    } 
    lazy val myExpensiveList = { 
    val l = // ... expensive stuff 
    l 
    } 
} 
+0

是的 - 這正是我所做的,但從「統一訪問原則」的角度來看,這似乎是一個恥辱。當你需要 – 2010-01-28 17:57:10

2

一個val沒有按沒有參數,因爲它被計算並存儲在一個字段中。但我可能只是將您在郵件列表上最近兩天的廣泛帖子轉給您。

或者,讓我們從Java的角度來考慮它,因爲Scala在jvm級別與Java兼容,並且它肯定必須遵守jvm規則。讓我們先從第一類:

abstract class X { 
    def expensiveOperation(p: Int => Boolean) : List[Int] 
} 

現在,讓我們來擴展它:

abstract class Y extends X { 
    override val expensiveOperation: ((Int) => Boolean) => List[Int] 
} 

因此,從Java中,我們知道,類X有方法expensiveOperation,接收Function1[Int, Boolean]並返回List[Int]

現在我們去上課Y。當然,它必須定義相同的方法,但它也必須定義吸氣器expensiveOperation,它不接收參數並返回Function1[Function1[Int, Boolean],List[Int]]

只要這種附加方法也不存在於X之內,則可能是可行的。所以讓我們定義它:

class Z extends Y { 
    override val extensiveOperation = new Function1[Function1[Int, Boolean], List[Int]] { 
    def apply(p: Int => Boolean) = List range (1, 10) filter p 
    } 
} 

這是如何定義的?斯卡拉是否將apply的身體作爲expensiveOperation(接收參數而不是吸氣者)的身體複製?它可能仍然可行。讓我們嘗試別的東西,但:

class W(f: ((Int) => Boolean) => List[Int]) extends Y { 
    override val extensiveOperation = f 
} 

現在,我們如何重寫extensiveOperation接收參數?我想我們可以這樣寫:

override def extensiveOperation(p: Int => Boolean) = extensiveOperation.apply(p) 

這是可行的。但我個人認爲這有點複雜。我的建議是:寫一個簡短的SID,並在Scala郵件列表上獲得一些協議。但是,如果沒有代碼來實現它,我認爲它不太可能被採用 - Scala必須跟蹤每個函數val來判斷它是否重寫def

+0

在過去的幾天裏我的工作已經有點(讀了很多)狂熱(閱讀:幾個月),而且我還沒有跟上郵件的標準!在我看來,*可能*是相同的東西,但我不是語言設計者,從來沒有在我的生活中編寫過編譯器!所以我不確定會有來自我的參考實現... – 2010-01-28 23:38:46

+0

我現在正趕上郵件列表。多麼奇怪的是,有一個關於我恰好在同一時間想到的主題的巨大討論! – 2010-01-29 15:32:27