2014-11-29 33 views
5

Ben Functors nasıl çalıştığını anlamaya çalışıyorum, bu yüzden buraya bu konuda okuyun: http://learnyouahaskell.com/making-our-own-types-and-typeclasses#the-functor-typeclassHaskell - Functors

Bir harita alır ve (bir listedir) değerlerin toplamını hesaplayan bir işleve sahiptir.

reduce :: Map String [Int] -> Map String Int 
reduce = fmap sum 

Gerçekten fmap nasıl çalıştığını anlamadı yüzden bu konuda okumak ve kendi versiyonunu yapmaya çalıştı. Bunu gerçekten test edemem çünkü Harita zaten Haskell kütüphanesinde tanımlanmıştır.

Peki bu doğru mu?

instance Functor (Map k) where 
    fmap f fromList[] = [] 
    fmap f fromList[(k, v): xs] = (f v) fmap xs 
+1

doğrudan alakalı değil, ama ben http://adit.io/posts/2013 Functors açıklarken bu blog yazısı çok net bulundu: Eğer gerçekten deneme yapmak istediğiniz, bir newtype ilan edebilir -04-17-functors, _applicatives, _and_monads_in_pictures.html – chi

+0

Harika görünüyor! Teşekkürler, ben kontrol edeceğim. –

+2

"Harita zaten tanımlanmış olduğundan gerçekten test edemiyorum" - Kodunuzu test etmek için bir "Functor" örneğini bildirmeniz gerekmez. Sadece işlevinizi kendi başınıza tanımlayın ve mevcut bir işlevle (ör., "Fmap") çatışmayan bir şeye yeniden adlandırın. –

cevap

6

Örneğiniz ahlaki açıdan doğru yolda, ancak içinde birkaç hata var. En belirgin olanı, fromList bir kurucu olmadığı için fromList ... modelini eşleştirememenizdir. Asıl kurucular Data.Map modülü tarafından dışa aktarılamaz, dolayısıyla eşleştirmeyi hiç yapamayız - bu, bu modülde kullanılan iç ağaç temsiline erişemediğinizden emin olmak ve muhtemelen bazı değişmezleri kırmaktır.

Daha iyi bir örnek, örn. Bu temel olarak temel değer çiftleri yapılmış bir ilişki listesine bütün ilk döner

instance Ord k => Functor (Map k) where 
    fmap f m = fromList (map modify (toList m)) 
     where modify (k,v) = (k, fv) 

(@gallais bahseder kısıtlama Ord k, Map gereklidir), daha sonra f uygulanması her değeri değişir ve daha sonra ilk oluşturur geri. Harita modülünde fiili örnek bir ara listeye geçmesine yok - Daha özlü, bu korkunç verimli değildir unutmayın

instance Ord k => Functor (Map k) where 
    fmap f = fromList . map (\(k,v) -> (k,f v)) . toList 

olarak yazılabilir.

Son olarak, Harita modülü zaten sizin için bir tane sağladığından kendi örneğinizi tanımlayamayacağınızı unutmayın. senin örneğe

newtype MyMap k v = MyMap { unMyMap :: Map k v } 

instance Functor (MyMap k) where 
    fmap f = MyMap . fromList . map (\(k,v) -> (k,f v)) . toList . unMyMap 
+2

Muhtemelen 'Functor' örneğinde' Ord k' kısıtlamasına ihtiyacınız var. Ayrıca, anecdotically, tanımı daha da başarılı hale getirilebilir ki, çünkü ((,) k) 'nin kendisi bir functor'dır. 'FromList yazabilirsiniz. fmap (fmap f). toList'. – gallais