2012-01-24 13 views
9

Just [1] ve Just [2]'dan Just [1, 2]'a giden Haskell'de neyin açık bir şekilde görülmesi gerektiğini yapmaya çalışıyorum. Ancak, alakalı ancak yararsız sayfalar bulmaya devam ederken çevrimiçi olarak hiçbir şey bulamıyorum. Peki bunu nasıl başarabilirsin?Haskell'de Birleştirme/Ekleme

cevap

15

Sen liftA2 (++) kullanabilirsiniz:

liftA2 (++) :: Maybe [a] -> Maybe [a] -> Maybe [a] 

liftA2

sadece Applicative bir ikili işlevini kaldırır. Applicative s, bir bağlamdaki keyfi argümanların işlevlerini kaldırmak için tasarlanmıştır, bu nedenle bunlar için mükemmeldir. Bu durumda, Applicative kullanıyoruz Maybe. Bunun nasıl çalıştığını görmek için, tanım bakabilirsiniz: (a -> b) -> f a -> f b:

liftA2 :: (Applicative f) => (a -> b -> c) -> f a -> f b -> f c 
liftA2 f a b = f <$> a <*> b 

(<$>) sadece f içindeki bir işletim saf değerler üzerine herhangi bir işlev kaldırır. (Eğer Functor s aşina eğer, fmap için sadece bir takma ad.) Maybe için:

_ <$> Nothing = Nothing 
f <$> Just x = Just (f x) 

(<*>) biraz daha zordur: bu f içinde bir değere f içinde bir işlev geçerlidir: f (a -> b) -> f a -> f b. Maybe için:

Just f <*> Just x = Just (f x) 
_ <*> _ = Nothing 

(Aslında, f <$> xMaybe için Just f <*> x olduğu pure f <*> x aynı şey söz konusudur.) Yani

, biz liftA2 (++) tanımını genişletebilirsiniz:

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 

Gerçekten de, herhangi bir argüman sayısını herhangi bir Applicative, j'ye yükseltmek için bu operatörleri kullanabiliriz. liftA2 modelini takip ederek. Bu uygulama stili olarak adlandırılır ve deyimsel Haskell kodunda çok yaygındır. Bu durumda, a ve b zaten değişkenler ise, (++) <$> a <*> b yazarak doğrudan kullanmak için daha deyimsel olabilir. (Diğer yandan, kısmen uyguluyorsanız - Daha yüksek dereceden işlevine geçmek demek - o liftA2 (++) tercih edilir.) Hiç çalışırken kendinizi bulmak eğer öyleyse

Her Monad, bir Applicative olduğunu Bir işlevi bir bağlamda "kaldır", Applicative muhtemelen sizin aradığınız şeydir. @ Ehird cevabı büyük ise

+0

Awesome :) Teşekkürler, beni saçlarımı yırtarak kurtardın. [2] 've' Sadece [3] '-' '[2, 3] için bir eşdeğer olduğunu bilemez misiniz? :) –

+4

@DeanBarnes: '(2 :) <$> Sadece [3]' –

+0

Fantastik cevap, teşekkürler @ehird! Bu temelde şu andan itibaren referansım :) –

3

, ben formda bir noobish çözümü kullanılmış olurdu: şunu kullanabilirsiniz

mergeJust a b = do 
    a' <- a 
    b' <- b 
    return (a' ++ b') 
+2

+1 bile noobs, bu sorunu çözebilir. Aynı zamanda bir monad anlama olarak da yazabilirsiniz: '[a '++ b' | Bir '<- a, b' <- b] ' –

3

Just s listesine çözüm genişletmek için

fmap join $ sequence [Just[1],Just[2],Just[3]] 
-- Just [1,2,3] 
1

Diğer çözümlerde bahsedilmediğinden, burada söyleyeceğim. Görevin yerine getirilmesinin en kolay yolu, bence, Data.Monoid'dan <> (veya mappend) kullanmaktır.

import Data.Monoid 

Just [1,2] <> Just [7,8] == Just [1,2,7,8] 

Ancak unutmayın ehird en uygulamalı çözümü aksine bu çözüm, Nothing değerlerine kısa devre olacak.

Just [1,2] <> Nothing ---> Just [1,2] 
--However 
(++) <$> Just [1,2] <*> Nothing ---> Nothing 
+0

Bazen bu bazen uygun davranış olmayabilir. –