2013-04-12 126 views
4

內置支持返回結果的聲明嗎?Scala中的函數聲明

這是非常非功能來做到這一點:

def addPositive(a: Int, b: Int) = { 
    assert(a > 0 && b > 0) 
    a + b 
    } 

我寧願做類似的東西:

def addPositive(a: Int, b: Int) = 
    assert(a > 0 && b > 0)(a + b) 

這樣我能避免斷言的必要環節。 (後者不編譯) 是否有類似的東西可用?

+0

順便提一下,有*交*條件:['Predef.ensuring'](https://github.com /scala/scala/blob/v2.10.1/src/library/scala/Predef.scala#L49)。 –

+0

是的,我也找到了。但我需要的是一個先決條件。 – Felix

+3

assert背後的主要思想是當條件不滿足時拋出異常。拋出異常是一件非常無用的事情。斷言本質上是必不可少的。試圖讓它們更具功能性對我來說似乎很陌生。 –

回答

14

函數式編程對待作爲純數學函數(理想)。那麼說數學的方式是說一個函數對某些參數不起作用,並且必須爆炸?

Partial Functions

事實證明,Scala有這個概念相當不錯的支持:PartialFunction。 這是你將如何使用部分功能重寫代碼:

val addPositive: PartialFunction[(Int, Int), Int] = { 
    case (a, b) if a > 0 && b > 0 => a + b 
} 

這樣做有幾個好處:

如果你用錯誤的參數調用它,它會拋出一個異常MatchError

addPositive(-1, 2) => Exception in thread "main" scala.MatchError: (-1,2) (of class scala.Tuple2$mcII$sp) 

實際上,你可以品嚐功能的域來檢查某些值是非常適合作爲函數的參數:

addPositive.isDefinedAt(-1, 2) => false 

如果你想給函數適用於一些參數,讓無論是結果,或者一些值指示失敗,你可以lift它返回Option

addPositive.lift(-1, 2) => None 
addPositive.lift(1, 2) => Some(12) 

您可以與其他功能組成它提供回退在參數無效的情況下:

val fallback: PartialFunction[(Int, Int), Int] = { case (a, b) => Int.MinValue } 
val f = addPositive orElse fallback 

f(-1, 2) => -2147483648 

或自定義的方式來對待錯誤:

它與標準庫運作良好:看Seq.collectSeq.collectFirst

另外PartialFunction是一個正常的一元函數,所以你也繼承了所有的函數操作。

這裏是在一篇文章中說明的Scala非常典雅部分功能:

Scala partial functions (without a PhD)

+0

我不認爲有更好的方法來回答這個問題。大! –

+0

@NikitaVolkov謝謝! –

+0

非常好,謝謝。唯一不好的是它很冗長。但是,你展示了一些非常好的點並很好地回答了我的問題! – Felix

4

你可以推出自己的實現:

def assert[T](cond: =>Boolean)(expr: =>T): T = { 
    assert(cond) 
    expr 
} 

你也可以使用的選項類型,以避免例外,但是這意味着你以後有模式匹配的結果:

def addPositive(a: Int, b: Int): Option[int] = 
    if (a > 0 && b > 0) Some(a + b) 
    else None 

這可以用與上面的assert變體類似的方式重構。

+3

是的。我不太喜歡這個:)我傾向於反對將自己的工具帶到一種語言。 – Felix

-5

前提條件是require函數,它幾乎完成了你想要的任務。你可以做

def addPositive(a: Int, b: Int) = 
    require (a > 0 && b > 0, a + b) 

有部分scala.Predef,所以他們總是包括在內。參數(示例中的a+b)是按名稱傳遞的,因此只有在條件不正確時纔會執行該參數。

requires總是被激活,如果你希望能夠停用它,你可以用assert弄得太,如:

assert(a > 0 && b > 0, a + b) 
+0

我認爲這不符合你的想法。 – Felix

+1

這取決於你的想法,我認爲:它會拋出一個1IllegalArgumentException異常''消息'需求失敗'加上'a + b'的值 – Chirlo

+2

對不起,但這顯然不是我所要求的。 – Felix