Haskell'de Nokta İşleci: daha fazla açıklamaya ihtiyacınız var


87

Nokta operatörünün bu Haskell kodunda ne yaptığını anlamaya çalışıyorum:

sumEuler = sum . (map euler) . mkList

Kaynak kodun tamamı aşağıdadır.

Benim anlayışım

Nokta operatörü iki işlevi sumve sonucunu map eulerve sonucunu mkListgirdi olarak alıyor.

Ancak, sumbir işlev değil, işlevin argümanıdır, değil mi? Peki burada neler oluyor?

Ayrıca ne (map euler)yapıyor?

Kod

mkList :: Int -> [Int]
mkList n = [1..n-1]

euler :: Int -> Int
euler n = length (filter (relprime n) (mkList n))

sumEuler :: Int -> Int
sumEuler = sum . (map euler) . mkList

Yanıtlar:


139

Basitçe ifade etmek gerekirse, .matematikte olduğu gibi fonksiyon kompozisyonu:

f (g x) = (f . g) x

Sizin durumunuzda, şu sumEulerşekilde tanımlanabilecek yeni bir işlev yaratıyorsunuz :

sumEuler x = sum (map euler (mkList x))

Örneğinizdeki stil, "noktasız" stil olarak adlandırılır - işlevin argümanları atlanmıştır. Bu, çoğu durumda daha net kod sağlar. (İlk gördüğünüzde mırıldanmak zor olabilir, ancak bir süre sonra alışacaksınız. Bu yaygın bir Haskell deyimidir.)

Hala kafanız karışıksa, .UNIX borusu gibi bir şeyle ilişki kurmak yardımcı olabilir . Eğer fbireyin çıkışı olur gkimin çıkışı olur lar girdi, ' h'nin girişi, sizin gibi komut satırında böyle yazardım f < x | g | h. Haskell'de, .UNIX gibi çalışır |, ancak "geriye doğru" - h . g . f $ x. Diyelim ki bir listeyi işlerken bu gösterimi oldukça yararlı buluyorum. Gibi hantal bir yapı yerine, map (\x -> x * 2 + 10) [1..10]sadece yazabilirsiniz (+10) . (*2) <$> [1..10]. (Ve bu işlevi yalnızca tek bir değere uygulamak istiyorsanız; bu (+10) . (*2) $ 10. Tutarlıdır!)

Haskell wiki'nin biraz daha ayrıntılı olan iyi bir makalesi var: http://www.haskell.org/haskellwiki/Pointfree


1
Küçük kelime oyunu: İlk kod parçacığı aslında geçerli Haskell değil.
SwiftsNamesake

2
@SwiftsNamesake Haskell'de akıcı olmayan bizler için, tek eşittir işaretinin burada anlamlı olmadığını mı söylüyorsunuz? (Yani pasajın " f (g x)= (f . g) x" biçimlendirilmiş olması gerekir ?) Veya başka bir şey?
user234461

1
@ user234461 Kesinlikle, evet. Bunun ==yerine, geçerli standart Haskell istiyorsanız ihtiyacınız olacak.
SwiftsNamesake

Üstteki küçük pasaj sadece altın. Buradaki diğer cevaplar gibi doğru ama o pasaj doğrudan kafamda sezgisel olarak tıklandı, bu da cevabınızın geri kalanını okumayı gereksiz kıldı.
Tarick Welling

24

. operatör işlevleri oluşturur. Örneğin,

a . b

Nerede bir ve b fonksiyonları yeni toplamak vardır fonksiyonu o zaman bağımsız değişkenler, b çalışır bu sonuçlar üzerinde. Senin kodun

sumEuler = sum . (map euler) . mkList

şununla tamamen aynıdır:

sumEuler myArgument = sum (map euler (mkList myArgument))

ama umarım okuması daha kolaydır. Map euler etrafında parens olmasının nedeni , oluşturulmakta olan 3 fonksiyonun olduğunu daha net hale getirmesidir: sum , map euler ve mkList - map euler tek bir fonksiyondur.


24

sumHaskell Prelude'deki bir fonksiyondur, bir argüman değildir sumEuler. Türüne sahip

Num a => [a] -> a

İşlev bileşimi operatörünün . türü vardır

(b -> c) -> (a -> b) -> a -> c

Böylece sahibiz

           euler           ::  Int -> Int
       map                 :: (a   -> b  ) -> [a  ] -> [b  ]
      (map euler)          ::                 [Int] -> [Int]
                    mkList ::          Int -> [Int]
      (map euler) . mkList ::          Int ->          [Int]
sum                        :: Num a =>                 [a  ] -> a
sum . (map euler) . mkList ::          Int ->                   Int

Bunun Intaslında Numtip sınıfının bir örneği olduğuna dikkat edin .


11

. operatör, fonksiyon bileşimi için kullanılır. Tıpkı matematik gibi, f (x) ve g (x) f fonksiyonlarına ihtiyacınız varsa. g, f (g (x)) olur.

map, bir listeye bir işlev uygulayan yerleşik bir işlevdir. Fonksiyonun parantez içine alınmasıyla, fonksiyon bir argüman olarak değerlendirilir. Bunun için bir terim körlemedir . Buna bakmalısın.

Yaptığı şey, diyelim ki iki argüman içeren bir işlevi almasıdır, euler argümanını uygular. (harita euler) değil mi? ve sonuç, yalnızca bir argüman alan yeni bir işlevdir.

toplam. (harita euler). mkList temelde hepsini bir araya getirmenin süslü bir yoludur. Söylemeliyim ki, Haskell'im biraz paslanmış ama belki bu son işlevi kendiniz bir araya getirebilirsiniz?


6

Haskell'de Nokta Operatörü

Nokta operatörünün bu Haskell kodunda ne yaptığını anlamaya çalışıyorum:

sumEuler = sum . (map euler) . mkList

Kısa cevap

Noktasız eşdeğer kod, yani

sumEuler = \x -> sum ((map euler) (mkList x))

veya lambda olmadan

sumEuler x = sum ((map euler) (mkList x))

çünkü nokta (.) işlev bileşimini gösterir.

Daha uzun cevap

İlk olarak, kısmi uygulama basitleştirmek izin euleriçin map:

map_euler = map euler
sumEuler = sum . map_euler . mkList

Şimdi sadece noktalara sahibiz. Bu noktalarla ne gösterilir?

Gönderen kaynağı :

(.)    :: (b -> c) -> (a -> b) -> a -> c
(.) f g = \x -> f (g x)

Bu nedenle (.)bir oluşturma operatör .

Oluştur

Matematikte, f (x) ve g (x), yani f (g (x)) fonksiyonlarının bileşimini şöyle yazabiliriz:

(f ∘ g) (x)

"f, g ile oluşturulmuş" olarak okunabilir.

Yani Haskell'de, f ∘ g veya g ile oluşan f yazılabilir:

f . g

Kompozisyon ilişkiseldir, yani kompozisyon operatörü ile yazılan f (g (h (x))) parantezleri belirsizlik olmadan dışarıda bırakabilir.

Yani, (f ∘ g) ∘ h, f ∘ (g ∘ h) 'ye eşit olduğu için, basitçe f ∘ g ∘ h yazabiliriz.

Geri dönüyor

Daha önceki basitleştirmemize geri dönersek, bu:

sumEuler = sum . map_euler . mkList

sadece sumEulerbu işlevlerin uygulanmamış bir bileşimi olduğu anlamına gelir :

sumEuler = \x -> sum (map_euler (mkList x))

4

Nokta operatörü, soldaki ( sum) işlevi sağdaki işlevin çıktısına uygular . Senin durumunda, birlikte çeşitli işlevleri zincirleme ediyoruz - sen sonucunu geçiyoruz mkListiçin (map euler), ve sonra o sonucunu geçen sum. Bu site , bazı kavramlara iyi bir giriş içerir.

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.