2016-11-14 4 views
2

У меня есть объект x. Я собираюсь выполнить серию преобразований. Это легко выразить какИдиоматический способ выполнения условного преобразования

x.transformA.transformB.transformC 

Однако перед каждым преобразованием я должен также проверить состояние. Только если условие истинно, я должен выполнить преобразование. У меня есть два способа выразить это. Во-первых, нужно определить x как var.

var x = anObject 
if (x.condA) x = x.transformA 
if (x.condB) x = x.transformB 
if (x.condC) x = x.transformC 
// final result in x 

В качестве альтернативы, чтобы избежать вар, я определить ряд промежуточных переменных

val x0 = anObject 
val x1 = if (x0.condA) x0.transformA else x0 
val x2 = if (x1.condB) x1.transformB else x1 
val x3 = if (x2.condC) x2.transformC else x2 
// final result in x3 

Это кажется довольно громоздким, даже к ошибкам, когда я вырезать и вставить строки. Есть ли более идиоматический способ выразить это?

+0

типа объекта никогда не меняется? Из выражений выше, 'xi.transform' - тот же тип, что и' xi' – maasg

+0

Как насчет складки? – rethab

ответ

3

В качестве композиции из Function s можно выразить ряд условных преобразований. Таким образом, каждое преобразование может быть объявлено независимо и повторно использовано для создания новых преобразований.

В качестве примера:

val ta: MyClass => MyClass = {case x if x.condA => x.transformA 
           case x => x} 
val tb: MyClass => MyClass = {case x if x.condB => x.transformB 
           case x => x} 
val tc: MyClass => MyClass = {case x if x.condC => x.transformC 
           case x => x} 

Тогда мы можем составить те, чтобы сформировать нашу трансформацию:

val transformation = ta andThen tb andThen tc 
val transformedObj = transformation(x) 

Мы можем видеть выше, что мы повторяем ту же картину снова и снова. Чтобы избежать этого, мы могли бы сделать функцию, которая создает наши частичные функции, уменьшая шаблонный код:

def mkTf[T](cond: T => Boolean, transf: T => T): T => T = { 
    case x if cond(x) => transf(x) 
    case x => x 
} 

Тогда мы можем переписать нашу композицию, как:

val transformation = mkTf[MyClass](_.condA,_.transformA) andThen 
        mkTf[MyClass](_.condB,_.transformB) andThen 
        mkTf[MyClass](_.condC,_.transformC) 
+1

Что нужно для 'PartialFunction'? Функция 'Function' отлично работает здесь, так как она определена для каждого' x: T'. –

+0

@CyrilleCorpet Вы абсолютно правы. Я начал отвечать на мысль о том, чтобы добавить идентификационный код как «PartialFunction» назад ('orElse'), но затем перешел в другую мысль. Адаптированный ответ соответственно. Благодарю. – maasg

+0

Спасибо! Это избавляет меня от наличия промежуточных переменных. –