Существуют ли типы с побочными методами, которые возвращают исходный тип?

Часто мне хочется привязать побочную функцию к концу вызова другого метода более функциональным способом, но я не хочу преобразовывать исходный тип в Unit. Предположим, у меня есть метод read, который ищет запись в базе данных и возвращает Option[Record].

def read(id: Long): Option[Record] = ...

Если read возвращает Some(record), то я мог бы закэшировать это значение и двигаться дальше. Я мог бы сделать что-то вроде этого:

read(id).map { record =>
    // Cache the record
    record
}

Но я хотел бы избежать приведенного выше кода и получить что-то более похожее на это, чтобы было более понятно, что происходит:

read(id).withSideEffect { record =>
    // Cache the record
}

Где withSideEffect возвращает то же значение, что и read(id). После поиска сверху и снизу я не могу найти ни одного метода для любого типа, который делает что-то подобное. Самое близкое решение, которое я могу придумать, это использовать неявную магию:

implicit class ExtendedOption[A](underlying: Option[A]) {
    def withSideEffect(op: A => Unit): Option[A] = {
        underlying.foreach(op)
        underlying
    }
}

Есть ли какие-то типы Scala, которые я мог пропустить с помощью таких методов? И есть ли потенциальные конструктивные недостатки при использовании такого метода?


person Michael Zajac    schedule 10.09.2014    source источник
comment
В Scala есть поддержка одноэлементных типов (не путать с объектами), которые представляют собой тип, соответствующий конкретному экземпляру. Например, метод def f(a: A): a.type должен возвращать предоставленный экземпляр A.   -  person J Cracknell    schedule 10.09.2014
comment
Дизайн меня устраивает, сам пользуюсь.   -  person samthebest    schedule 10.09.2014
comment
Задумывались ли вы о комбинаторах Kestrel? В примере он используется для ведения журнала, но вы можете легко адаптировать его для кэширования.   -  person Ende Neu    schedule 10.09.2014


Ответы (2)


Future.andThen (scaladoc) принимает побочный эффект и возвращает будущее текущего значения в облегчают беглую цепочку.

Тип возвращаемого значения не this.type.

См. также повторяющиеся вопросы о касании.

person som-snytt    schedule 10.09.2014
comment
+1 за ссылку на кран. Кажется, это точно соответствует потребностям ОП. - person The Archetypal Paul; 10.09.2014

Вы можете использовать scalaz для «явной аннотации» побочных функций. В scalaz 7.0.6 это монада IO: http://eed3si9n.com/learning-scalaz/IO+Monad.html

Он устарел в scalaz 7.1. Я бы сделал что-то подобное с Task

val readAndCache = Task.delay(read(id)).map(record => cacheRecord(record); record)
readAndCache.run // Run task for it's side effects
person Eugene Zhulenev    schedule 10.09.2014
comment
Есть ли какая-нибудь информация об этом прекращении поддержки? Это не аннотировано и не задокументировано как таковое в источнике. - person Hugh; 10.09.2014
comment
Не могу найти сейчас. В списке рассылки обсуждалось, что Task должен заменить IO. Но похоже, что в 7.1 этого не произошло. Они оба очень похожи семантически. - person Eugene Zhulenev; 10.09.2014