2017-02-09 3 views
2

Есть ли какая-то операция «tee» на Option в стандартной библиотеке Scala? Лучшее, что я мог найти, это foreach, однако его тип возврата Unit, поэтому он не может быть прикован.Операция «tee» по типу опций Scala?

Это то, что я ищу: с учетом экземпляра Option выполнить некоторую операцию с побочными эффектами по ее значению, если опция не пуста (Some[A]), в противном случае ничего не делать; возвратите вариант в любом случае.

У меня есть собственная реализация с использованием неявного класса, но мне интересно, есть ли более простой способ сделать это без неявного преобразования:

object OptionExtensions { 
    implicit class TeeableOption[A](value: Option[A]) { 
    def tee(action: A => Unit): Option[A] = { 
     value foreach action 
     value 
    } 
    } 
} 

Пример кода:

import OptionExtensions._ 

val option: Option[Int] = Some(42) 
option.tee(println).foreach(println) // will print 42 twice 

val another: Option[Int] = None 
another.tee(println).foreach(println) // does nothing 

Любой предложения?

+1

Я не предполагаю, что вы увидите что-либо, что неявно вводит побочные эффекты в функцию в стандартной библиотеке. –

+2

Побочные эффекты и функциональное программирование не являются друзьями. –

+0

Нет. http://stackoverflow.com/questions/9671620/how-to-keep-return-value-when-logging-in-scala http: // stackoverflow.com/questions/16742060/analog-to-rubys-tap-method-in-scala –

ответ

3

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

Вот краткий пример:

object KCombinator { 
    def tap[A](a: A)(action: A => Any): A = { 
    action(a) 
    a 
    } 
} 

import KCombinator._ 

val func = ((_: Option[Int]).getOrElse(0)) 
    .andThen(tap(_)(println)) 
    .andThen(_ + 3) 
    .andThen(tap(_)(println)) 

Если мы называем наш FUNC с аргументом Option(3) результат будет Int со значением 6 и это, как консоль будет выглядеть следующим образом:

+0

Это должен быть принятый ответ – eladHayun

+0

... за исключением того, что он не работает. :) Вызов func (None) приводит к тому, что 0 и 3 печатаются на stdout, что не является обязательным. Тем не менее я принял ответ, так как идея была правильной и использовала 'def tap [A] (действие: A => Any) (значение: A): Option [A] = {action (value); Some (value)} 'делает трюк:' option.flatMap (tap (println)). Foreach (println) 'печатает 42 дважды, если опция не пуста; иначе он ничего не делает. – proskor

+0

Это печать 0 и 3 только потому, что я вызвал getOrElse (0). Возврат Некоторый (значение) неверен, потому что у вас будет вложенный вариант опциона ... вы получите идею, которая не то, что вы хотите. Я не думаю, что это имеет большое значение для короткого замыкания внутри самого крана. Вы можете моделировать математику внутри действия крана, чтобы получить то же самое поведение, которое вы ищете. – NetanelRabinowitz

0

Существует нет существующего способа выполнить это в стандартной библиотеке, поскольку побочные эффекты минимизированы и изолированы в функциональном программировании. В зависимости от ваших фактических целей есть несколько разных способов идиоматически выполнить вашу задачу.

В случае выполнения большого количества команд println, вместо того, чтобы посыпать их по всему алгоритму, вы обычно собираете их в коллекции, а затем делаете один foreach println в конце. Это минимизирует побочные эффекты до наименьшего возможного воздействия. Это происходит с любым другим побочным эффектом. Попытайтесь найти способ сжать его в наименьшее возможное пространство.

Если вы пытаетесь связать серию «действий», вы должны посмотреть на futures. Фьючерсы в основном рассматривают действие как ценность и предоставляют множество полезных функций для работы с ними.

1

Просто используйте карту, и ваши функции, связанные с действием, соответствуют action: A => A, а не action: A => Unit.

def tprintln[A](a: A): A = { 
    println(a) 
    a 
} 
another.map(tprintln).foreach(println) 
Смежные вопросы