Mono-traversable'dan “concatMap” ortak argümanı nasıl “çıkarabilir”?


9

Haskell öğreniyorum ve anlamak zor bulduğum bu davranış üzerine tökezlediğimde Yesod için basit bir DB-tohum programı yapıyordum:

testFn :: Int -> Bool -> [Int]
testFn a b = if b then replicate 10 a else []

Yesod GHCI oturumu:

$ :t concatMap testFn [3]
concatMap testFn [3] :: Bool -> [Int]
$ (concatMap testFn [1,2,3]) True
[1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3]

Her nasılsa, bu ikinci "Bool" ü eşlemelerin her birinden tek bir kıvrımlı argümana "çekebildi".

Standart temel Prelude GHCI oturumu bu ifadeyi derlemeyi bile reddeder:

$ :t concatMap testFn [3]
error:
     Couldn't match type 'Bool -> [Int]' with '[b]'
      Expected type: Int -> [b]
        Actual type: Int -> Bool -> [Int]
     Probable cause: 'testFn' is applied to too few arguments
      In the first argument of 'concatMap', namely 'testFn'
      In the expression: concatMap testFn [3]

Yesod , kendine ait olan tek yönlü kitaplığı kullanıyor concatMap:

$ :t concatMap
concatMap
  :: (MonoFoldable mono, Monoid m) =>
     (Element mono -> m) -> mono -> m

Şu anki Haskell anlayışımda, tiplerin burada nasıl dağıldığını anlayamadım. Birisi bana (mümkün olduğunca yeni başlayanlara yönelik) bu hile nasıl yapıldığını açıklayabilir mi? testFnYukarıdakilerin hangi kısmı Element monotipe uygundur?

Yanıtlar:


6

Bildiğimiz bazı türleri listeleyerek başlıyoruz. (Sayıların Intbasitlik için olduğunu iddia ediyoruz - bu gerçekten alakalı değil.)

testFn :: Int -> Bool -> [Int]
[1,2,3] :: [Int]
True :: Bool

(concatMap testFn [1,2,3]) Trueaynıdır concatMap testFn [1,2,3] True, yani concatMaptüm bu argümanları uyan bir türü olmalıdır:

concatMap :: (Int -> Bool -> [Int]) -> [Int] -> Bool -> ???

???sonuç türü nerede . İlişkilendirme kuralları nedeniyle ->sağ tarafla ilişkilendirildiğini, bu nedenle yukarıdaki yazmanın aynı olduğunu unutmayın:

concatMap :: (Int -> (Bool -> [Int])) -> [Int] -> (Bool -> ???)

Bunun üzerine genel türü yazalım. Benzerliği işaretlemek için birkaç boşluk ekliyorum.

concatMap :: (MonoFoldable mono, Monoid m) =>
             (Element mono -> m              ) -> mono  -> m
concatMap :: (Int          -> (Bool -> [Int])) -> [Int] -> (Bool -> ???)

Ah-ha! Biz seçerseniz Biz bir maç molarak Bool -> [Int]ve monosıra [Int]. Bunu yaparsak, kısıtlamaları yerine getiririz MonoFoldable mono, Monoid m(aşağıya bakın) ve ayrıca var Element mono ~ Int, bu yüzden her şey kontrol eder.

Biz sonucuna ???olduğu [Int]tanımından m.

Kısıtlamalar hakkında: MonoFoldable [Int]söyleyecek çok az şey var. [Int]Bir liste benzeri bir tipte açıkça Inteleman türü, ve bu dönüştürebilmek için yeterli MonaFoldableolan Intonun kadar Element.

Çünkü Monoid (Bool -> [Int])biraz daha karmaşık. A -> BEğer bir monoid ise B, herhangi bir fonksiyon tipinin bir monoid olduğunu varsayalım. Bunu, işlemi noktasal bir şekilde gerçekleştirerek takip eder. Özel durumumuzda, [Int]bir monoid olmaya güveniyoruz ve şunları elde ediyoruz:

mempty :: Bool -> [Int]
mempty = \_ -> []

(<>) :: (Bool -> [Int]) -> (Bool -> [Int]) -> (Bool -> [Int])
f <> g = \b -> f b ++ g b

1
Harika bir açıklama! Tipleri açıklama ve hizalama şekliniz sadece görmek istediğim şeydi, teşekkürler!
dimsuz
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.