2011-04-02 17 views
14

Bunlar Haskell'deki ilk keşiflerim, bu yüzden açık olması gerekirse beni affet.concatMap oluşturmak için concat ve harita oluşturma: neden f?

Tüm öğleden sonraları, kendi liste türüm (tipik Eksileri) kullanarak, 99 questions on HaskellWiki eğitimini inceleyerek Haskell ile oynuyordum. Devam ettiğim gibi "belirgin" işlevleri ekledim ve bunları olabildiğince kısa bir şekilde yapmaya çalıştım (mümkün olduğunda noktadan notasyonu kullanmadan)

12. sorun, çalışma uzunluğu kodlanmış bir listenin kodunun çözülmesiyle ilgilidir.

> decode [Multiple 5 'a', Single 'b', Multiple 2 'c'] 
"aaaaabcc" 

ve sonra, her elemanının kodunu sonucu (bu konuda teşekkür Google) concatmap kullanma hakkında düşündü ve nihayet GHCi hızla teyit benim okumaları, içinde concatMap gibi bir şey gördüğünü hatırladı: yani :

O reimplement tarafından açıkça görülecek biçimde benziyordu concatMap: Bunun dışında

concatMap :: (a -> [b]) -> [a] -> [b] 
concatMap = concat . map 

GHCi oldukça şikayetçi:

List.hs:110:15: 
    Couldn't match expected type `[a] -> [b]' 
       with actual type `[a0]' 
    Expected type: [[a0]] -> [a] -> [b] 
     Actual type: [[a0]] -> [[a0]] 
    In the first argument of `(.)', namely `concat' 
    In the expression: concat . map 

bunu çözemedim, bu yüzden web üzerinde baktı ve

concatMap f = concat . map f 

Ve tip besbelliolduğundan bu f, neden gerekli olduğunu oldukça anlamıyorum: Prelude başvurulan tanım aslında İmza tarafından belirtildiği şekilde...

Neden f burada gereklidir? standart tanımlı başlayarak

cevap

15

,

concat . map f 
≡ concat . (map f) 
≡ \x -> concat ((map f) x) 

İlk tanım verir: concat[[a]], listelerin listesi alırken, (map f) :: [a] -> [b] çünkü kontrol yazın etmez

(concat . map) f 
≡ (\x -> concat (map x)) f 
≡ concat (map f) 

.

Sorunda gösterilen belirli hata iletisinin, yukarıdaki tür denetim hatasını bildirmediğini unutmayın. Verilen iletinin,numaralı [a] -> [b] dönüş türünü [a0], concat dönüş türüyle uzlaştırılamadığını bildirmesi gerekir. Tür imza kapalı bırakırsanız, yanıttır: concat argümanı tip map dönüş türünü mutabık kılınırken İşte

 
    Couldn't match type ‘[a1] -> [b]’ with ‘[[a]]’ 
    Expected type: (a1 -> b) -> [[a]] 
     Actual type: (a1 -> b) -> [a1] -> [b] 
    Relevant bindings include 
     concatMap :: (a1 -> b) -> [a] (bound at :49:5) 
    Probable cause: ‘map’ is applied to too few arguments 
    In the second argument of ‘(.)’, namely ‘map’ 
    In the expression: concat . map 

yazın hata oluşur. Bu durum, tür denetiminin neden başarısız olduğuna dair bir ipucu içerdiğinden, hata ayıklama için daha yararlıdır.

+1

Ah! '' ''In sağ tarafındaki işlevlerin tek bir argümanı beklemesini söylemek doğru mu? (Körelmeden önce 2 gibi harita değil mi?) Ayrıca, bunu ücretsiz bir tarzda yazmanın bir yolu var mı? –

+1

@Matthiew Haskell'deki her işlev tek bir argümanı kabul eder.Örneğin, 'map' bir işlevi kabul eder ve bir işlevi döndürür; g = map f', sırayla bir listeyi kabul eder ve bir eleman döndürür. Ayrıca, önemli bir şeyi hatırlayın: işlev uygulaması, herhangi bir operatörden daha sıkı bağlanır, bu, işleri anlamaya çok yardımcı olur. Bu noktayı nasıl yazacağımı bilmiyorum. – adamax

+0

kesinlikle başlayacağım tuhaf bir yolculuk :) 'replicateList :: Int -> Liste a -> Liste a (Problem 15, değiştirilmiş) 'replicateList = concatMap' olarak yazılabilir. replicate' ve iki argüman geçer, yazım denetimi yok. –

İlgili konular