Слияние / добавление 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
Другие вопросы по тегам