Ищет функцию Haskell, связанную с liftA2, но работает как <|> из Alternative - PullRequest
0 голосов
/ 09 ноября 2019

Рассмотрим эту liftA2 функцию:

liftA2 :: (Maybe a -> Maybe b -> Maybe c) -> Maybe a -> Maybe b -> Maybe c
liftA2 f Nothing  Nothing  = Nothing
liftA2 f (Just x) Nothing  = Nothing
liftA2 f Nothing  (Just y) = Nothing
liftA2 f (Just x) (Just y) = f x y

Это эквивалентно действительной liftA2 функции из Control.Applicative, но специализированной для Maybe. (а также liftM2 из Control.Monad)

Я ищу двоюродного брата этой функции, которая работает следующим образом:

mystery :: (Maybe a -> Maybe a -> Maybe a) -> Maybe a -> Maybe b -> Maybe c
mystery f Nothing  Nothing  = Nothing
mystery f (Just x) Nothing  = Just x
mystery f Nothing  (Just y) = Just y
mystery f (Just x) (Just y) = Just (f x y)

Ближайшая концепция, о которой я знаюравен <|>, но отбрасывает второе значение , если их два, тогда как я бы предпочел передать функцию для их объединения.

Как называется эта загадочная функция? На какой тип класса он работает? Какие условия я могу узнать в Google? Спасибо!

Ответы [ 2 ]

3 голосов
/ 09 ноября 2019

Если вы готовы принять сигнатуру другого типа, работающую с экземпляром полугруппы, а не с произвольной функцией f, то вы ищете новый тип Option из Data.Semigroup:

Prelude Data.Semigroup> Option Nothing <> Option Nothing
Option {getOption = Nothing}
Prelude Data.Semigroup> Option (Just [1]) <> Option Nothing
Option {getOption = Just [1]}
Prelude Data.Semigroup> Option Nothing <> Option (Just [2])
Option {getOption = Just [2]}
Prelude Data.Semigroup> Option (Just [1]) <> Option (Just [2])
Option {getOption = Just [1,2]}

Для произвольной функции вам нужно что-то, что довольно специализировано для Maybe - я не понимаю, как это могло бы работать для произвольного Applicative или Alternative.

2 голосов
/ 09 ноября 2019

Если я вас правильно понимаю, вас может заинтересовать класс Semialign из Data.Align, который предлагает zip -подобные операции, в которых не пропущены пропущенные элементы:

class Functor f => Semialign f where
  align :: f a -> f b -> f (These a b)
  align = alignWith id

  alignWith :: (These a b -> c) -> f a -> f b -> f c
  alignWith f as bs = f <$> align as bs

Вы можете написать

alignBasic :: Semialign f => (a -> a -> a) -> f a -> f a -> f a
alignBasic f = alignWith $ \case
  This a -> a
  That a -> a
  These a1 a2 -> f a1 a2
-- or just
alignBasic f = alignWith (mergeThese f)

Поскольку Maybe является экземпляром Semialign, alignBasic может использоваться в типе

alignBasic :: (a -> a -> a) -> Maybe a -> Maybe a -> Maybe a
...