Оператор Dot в Haskell: нужно больше объяснений

Я пытаюсь понять, что делает оператор точки в этом коде Haskell:

sumEuler = sum . (map euler) . mkList 

Весь исходный код приведен ниже.

Мое понимание

Оператор точки принимает две функции sum и результат map euler а результат mkList как вход.

Но, sum не является функцией, она является аргументом функции, правильно? и так, что здесь происходит?

Кроме того, что такое (map euler) ?

Код

 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 

    Проще говоря . является функциональной композицией, как и в математике:

     f (gx) = (f . g) x 

    В вашем случае вы создаете новую функцию sumEuler которая также может быть определена следующим образом:

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

    Стиль в вашем примере называется «бессмысленным» стилем – аргументы функции опущены. Во многих случаях это обеспечивает более четкий код. (Это может быть трудно получить в первый раз, когда вы его видите, но вы привыкнете к нему через некоторое время. Это обычная иксема Haskell.)

    Если вы все еще запутались, это может помочь связать . что-то вроде трубы UNIX. Если выход f становится входом g , выход которого становится входом h , вы должны записать это в командной строке, например f < x | g | h f < x | g | h f < x | g | h . В Haskell,. работает как UNIX | , но «назад» - h . g . f $ x h . g . f $ x h . g . f $ x . Я считаю, что это обозначение очень полезно, если, скажем, обработать список. Вместо некоторой громоздкой конструкции, такой как map (\x -> x * 2 + 10) [1..10] , вы можете просто написать (+10) . (*2) <$> [1..10] (+10) . (*2) <$> [1..10] . (И, если вы хотите применить эту функцию только к одному значению, это (+10) . (*2) $ 10 Согласование!)

    В вики Haskell есть хорошая статья с более подробной информацией: http://www.haskell.org/haskellwiki/Pointfree

    sum является функцией в Haskell Prelude, а не аргументом sumEuler . Он имеет тип

     Num a => [a] -> a 

    Оператор композиции функций . имеет тип

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

    Итак, у нас есть

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

    Заметим, что Int является экземпляром Num .

    . оператор выполняет функции. Например,

     a . b 

    Где a и b – это функция, это новая функция, которая запускает b в своих аргументах, а затем a на этих результатах. Ваш код

     sumEuler = sum . (map euler) . mkList 

    точно такая же, как:

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

    но, надеюсь, легче читать. Причина появления парсеров вокруг эйлера карты заключается в том, что он дает четкое представление о том, что есть три функции: sum , map euler и mkListmap euler – это единственная функция.

    . оператор используется для составления функции. Подобно математике, если у вас есть функции f (x) и g (x) f. g становится f (g (x)).

    map – это встроенная функция, которая применяет функцию к списку. Помещая функцию в круглые скобки, функция рассматривается как аргумент. Термин для этого – карри . Вы должны это посмотреть.

    Что делает, так это то, что он принимает функцию с двумя аргументами, она применяет аргумент euler. (карта Эйлера)? и результатом является новая функция, которая принимает только один аргумент.

    сумма. (эйлер карты). mkList – это, по сути, причудливый способ собрать все это вместе. Должен сказать, мой Haskell немного ржавый, но, может быть, вы можете объединить эту последнюю функцию самостоятельно?

    Оператор точки применяет функцию слева ( sum ) к выходу функции справа. В вашем случае вы объединяете несколько функций – вы передаете результат mkList (map euler) , а затем передаете результат этого sum . Этот сайт имеет хорошее представление о нескольких концепциях.

    Оператор Dot в Haskell

    Я пытаюсь понять, что делает оператор точки в этом коде Haskell:

     sumEuler = sum . (map euler) . mkList 

    Короткий ответ

    Эквивалентный код без точек, это просто

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

    или без лямбды

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

    потому что точка (.) указывает на состав функции.

    Более длинный ответ

    Во-первых, давайте упростим частичное применение euler для map :

     map_euler = map euler sumEuler = sum . map_euler . mkList 

    Теперь у нас есть точки. Что обозначают эти точки?

    Из источника :

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

    Таким образом, (.) – оператор компоновки .

    компоновать

    В математике мы могли бы написать состав функций f (x) и g (x), то есть f (g (x)), так как

    (f ∘ g) (x)

    который можно прочитать «f, состоящий из g».

    Таким образом, в Haskell f ∘ g или f, составленном с g, можно написать:

     f . g 

    Композиция ассоциативна, что означает, что f (g (h (x))), написанная с помощью оператора композиции, может не содержать круглых скобок без какой-либо двусмысленности.

    То есть, поскольку (f ∘ g) ∘ h эквивалентно f ∘ (g ∘ h), мы можем просто написать f ∘ g ∘ h.

    Откидывание назад

    Возвращаясь к нашему раннему упрощению, это:

     sumEuler = sum . map_euler . mkList 

    просто означает, что sumEuler является непримененным составом этих функций:

     sumEuler = \x -> sum (map_euler (mkList x)) 
    Давайте будем гением компьютера.