# Scala 函式柯里化(Function currying)

## 部分應用的函式

`Email` 類看起來仍然是這樣：

``````case class Email(
subject: String,
text: String,
sender: String,
recipient: String)
type EmailFilter = Email => Boolean
``````

``````    type IntPairPred = (Int, Int) => Boolean
def sizeConstraint(pred: IntPairPred, n: Int, email: Email) =
pred(email.text.size, n)
``````

``````    val gt: IntPairPred = _ > _
val ge: IntPairPred = _ >= _
val lt: IntPairPred = _ < _
val le: IntPairPred = _ <= _
val eq: IntPairPred = _ == _
``````

``````    val minimumSize: (Int, Email) => Boolean = sizeConstraint(ge, _: Int, _: Email)
val maximumSize: (Int, Email) => Boolean = sizeConstraint(le, _: Int, _: Email)
``````

``````    val constr20: (IntPairPred, Email) => Boolean =
sizeConstraint(_: IntPairPred, 20, _: Email)
val constr30: (IntPairPred, Email) => Boolean =
sizeConstraint(_: IntPairPred, 30, _: Email)
``````

### 從方法到函式物件

``````    val sizeConstraintFn: (IntPairPred, Int, Email) => Boolean = sizeConstraint _
``````

## 更有趣的函式

``````    def sizeConstraint(pred: IntPairPred)(n: Int)(email: Email): Boolean =
pred(email.text.size, n)
``````

``````    val sizeConstraintFn: IntPairPred => Int => Email => Boolean = sizeConstraint _
``````

`sizeConstraintFn` 接受一個 `IntPairPred` ，返回一個函式，這個函式又接受 `Int` 型別的引數，返回另一個函式，最終的這個函式接受一個 `Email` ，返回布林值。

``````    val minSize: Int => Email => Boolean = sizeConstraint(ge)
val maxSize: Int => Email => Boolean = sizeConstraint(le)
``````

``````    val min20: Email => Boolean = minSize(20)
val max20: Email => Boolean = maxSize(20)
``````

``````    val min20: Email => Boolean = sizeConstraintFn(ge)(20)
val max20: Email => Boolean = sizeConstraintFn(le)(20)
``````

### 函式柯里化

``````    val sum: (Int, Int) => Int = _   _
val sumCurried: Int => Int => Int = sum.curried
``````

### 函式化的依賴注入

``````    case class User(name: String)
trait EmailRepository {
def getMails(user: User, unread: Boolean): Seq[Email]
}
trait FilterRepository {
def getEmailFilter(user: User): EmailFilter
}
trait MailboxService {
def getNewMails(emailRepo: EmailRepository)(filterRepo: FilterRepository)(user: User) =
emailRepo.getMails(user, true).filter(filterRepo.getEmailFilter(user))
val newMails: User => Seq[Email]
}
``````

`MailboxService` 實現了這個方法，留空了欄位 `newMails`，這個欄位的型別是一個函式： `User => Seq[Email]`，依賴於 `MailboxService` 的元件會呼叫這個函式。

``````    object MockEmailRepository extends EmailRepository {
def getMails(user: User, unread: Boolean): Seq[Email] = Nil
}
object MockFilterRepository extends FilterRepository {
def getEmailFilter(user: User): EmailFilter = _ => true
}
object MailboxServiceWithMockDeps extends MailboxService {
val newMails: (User) => Seq[Email] =
getNewMails(MockEmailRepository)(MockFilterRepository) _
}
``````

Injection in Scala
”。