Есть ли название для такого подъема функции?

Я написал функцию Scala:

  def liftOrIdentity[T](f: (T, T) => T) = (a: Option[T], b: Option[T]) =>
    (a, b) match {
      case (Some(a), None) => Some(a)
      case (None, Some(b)) => Some(b)
      case (Some(a), Some(b)) => Some(f(a, b))
      case (None, None) => None
    }

Есть ли название у этого узора? Это не совсем аппликативный функтор из-за случаев 1 и 2. Не стесняйтесь отвечать кодом на Haskell или Scala.


person Felix    schedule 19.06.2013    source источник
comment
При сборе это flatten + reduce: List(a, b).flatten.reduceOption(f).   -  person senia    schedule 19.06.2013
comment
Это довольно сексуально! По сравнению со стеной уродства выше :) Подумайте о том, чтобы опубликовать это как ответ;) Не знал о reduceOption, это довольно круто!   -  person Felix    schedule 19.06.2013


Ответы (4)


При сборе это flatten + reduce:

List(a, b).flatten.reduceOption(f)
a ++ b reduceOption f // same result
person senia    schedule 19.06.2013
comment
Я оставлю это висеть, чтобы увидеть, есть ли еще предложения, но, вероятно, приму это :) - person Felix; 19.06.2013
comment
Я выбрал этот ответ, потому что он кратко решает проблему. Использование flatten здесь очень удобно, и я не знал о странной специфике reduceOption, но она прекрасно работает для моей проблемы. - person Felix; 20.06.2013
comment
@Felix: Обратите внимание, что на самом деле вам не нужно flatten здесь: a ++ b reduceOption f. - person senia; 20.06.2013
comment
Не могли бы вы сказать мне, откуда Option берет свой метод ++? scala-lang.org/api/current/index.html# scala.Option Я вижу его в списке, он работает в REPL, но он не расширяет TraversableLike и не реализует его: S Я запутался! - person Felix; 20.06.2013
comment
Option не имеет ++ метода. В документации он имеет зеленый цвет и Implicit information в описании. Как видно из Implicit information, существует неявное преобразование Option.option2Iterable. - person senia; 20.06.2013
comment
Спасибо, не знаю, почему я этого не читал :) Наверное, API иногда немного перегружен информацией. С другой стороны, если вы не развернетесь до полной подписи, подпись будет просто неправильной, верно? def ++[B](что: GenTraversableOnce[B]): Option[B] не возвращает Option[B]... - person Felix; 20.06.2013

Мне вспоминается класс типа Alternative в Haskell Control.Applicative:

class Applicative f => Alternative f where
    empty :: f a
    (<|>) :: f a -> f a -> f a

Общая версия вашей функции для любого экземпляра Alternative может выглядеть так:

liftOrAlternative :: (Alternative f) => (a -> a -> a) -> f a -> f a -> f a
liftOrAlternative f a b = f <$> a <*> b <|> a <|> b

ghci> liftOrAlternative (+) (Just 1) Nothing
Just 1
ghci> liftOrAlternative (+) (Just 1) (Just 2)
Just 3
ghci> liftOrAlternative (+) Nothing Nothing
Nothing

Я думаю, что для Scala ближайшей аналогией Alternative будет класс типов ApplicativePlus из Scalaz.

 def liftOrAlternative[A, F[_]: ApplicativePlus](f: (A, A) => A)(a: F[A], b: F[A]): F[A] =
   f.lift[F].apply(a, b) <+> a <+> b

Я признаю, что liftOrAlternative не очень хорошее имя. Прочитав ответ Твана ван Лаарховена, я думаю, что его предложение unionWith намного лучше выражает то, что на самом деле делает функция.

person Ben James    schedule 19.06.2013
comment
Есть, но относится к Map, а не к аппликативам вообще. - person Ben James; 19.06.2013
comment
Где тот, что на Maps? Единственные, которые я видел, относятся к сильно вдохновленным Haskell классам IntMap и LongMap. - person Mysterious Dan; 19.06.2013
comment
Я думаю, вы правы, это не для scala.collection.Map - person Ben James; 20.06.2013

Эта функция похожа на функцию контейнеров Haskell.

Data.Map.unionWith :: (a -> a -> a) -> Map k a -> Map k a -> Map k a

Я думаю, что unionWith — хорошее название для него в целом. Более обычным аппликативным оператором будет intersectionWith (он же zipWith).

Data.Map.intersectionWith :: (a -> b -> c) -> Map k a -> Map k b -> Map k c
person Twan van Laarhoven    schedule 19.06.2013

В Haskell есть нечто подобное, называемое подъемM2.

liftM2 :: Monad m => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
person Tobias Brandt    schedule 19.06.2013