Слияние / добавление Jasts в Haskell
Я пытаюсь сделать то, что должно быть ослепительно очевидно в Хаскеле, то есть Just [1]
а также Just [2]
в Just [1, 2]
, Однако я ничего не могу найти в Интернете, так как я продолжаю находить связанные, но бесполезные страницы. Итак, как вы этого достигнете?
4 ответа
Ты можешь использовать liftA2 (++)
:
liftA2 (++) :: Maybe [a] -> Maybe [a] -> Maybe [a]
liftA2
просто поднимает бинарную функцию в Applicative
, Applicative
Они были разработаны для подъема функций произвольных аргументов в контексте, поэтому они идеально подходят для этого. В этом случае Applicative
мы используем это Maybe
, Чтобы увидеть, как это работает, мы можем посмотреть на определение:
liftA2 :: (Applicative f) => (a -> b -> c) -> f a -> f b -> f c
liftA2 f a b = f <$> a <*> b
(<$>)
просто поднимает любую функцию на чистых значениях до одной действующей внутри f
: (a -> b) -> f a -> f b
, (Это просто псевдоним для fmap
, если вы знакомы с Functor
с.) Для Maybe
:
_ <$> Nothing = Nothing
f <$> Just x = Just (f x)
(<*>)
немного сложнее: он применяет функцию внутри f
к стоимости внутри f
: f (a -> b) -> f a -> f b
, За Maybe
:
Just f <*> Just x = Just (f x)
_ <*> _ = Nothing
(По факту, f <$> x
это то же самое, что pure f <*> x
, который Just f <*> x
за Maybe
.)
Таким образом, мы можем расширить определение liftA2 (++)
:
liftA2 (++) a b = (++) <$> a <*> b
-- expand (<$>)
liftA2 (++) (Just xs) b = Just (xs ++) <*> b
liftA2 (++) _ _ = Nothing
-- expand (<*>)
liftA2 (++) (Just xs) (Just ys) = Just (xs ++ ys)
liftA2 (++) _ _ = Nothing
Действительно, мы можем использовать эти операторы, чтобы поднять функцию любого числа аргументов в любой Applicative
, просто следуя схеме liftA2
, Это называется аппликативным стилем и очень распространено в идиоматическом коде на Haskell. В этом случае может быть даже более идиоматичным использовать его напрямую, написав (++) <$> a <*> b
, если a
а также b
уже переменные. (С другой стороны, если вы частично применяете это - скажем, чтобы передать его в функцию более высокого порядка - тогда liftA2 (++)
предпочтительнее.)
каждый Monad
является Applicative
так что если вы когда-нибудь попытаетесь "поднять" функцию в контекст, Applicative
это, вероятно, то, что вы ищете.
В то время как ответ @ehird хорош, я бы использовал нубистское решение в виде:
mergeJust a b = do
a' <- a
b' <- b
return (a' ++ b')
Развернуть решение до списка Just
с, вы могли бы использовать
fmap join $ sequence [Just[1],Just[2],Just[3]]
-- Just [1,2,3]
Поскольку это не было упомянуто в других решениях, я скажу это здесь. Самый простой способ выполнить вашу задачу, на мой взгляд, это использовать <>
(или же mappend
) от Data.Monoid
,
import Data.Monoid
Just [1,2] <> Just [7,8] == Just [1,2,7,8]
Однако обратите внимание, что это решение, в отличие от аппликативного решения ehird, не будет закорачивать Nothing
ценности.
Just [1,2] <> Nothing ---> Just [1,2]
--However
(++) <$> Just [1,2] <*> Nothing ---> Nothing