Вопрос

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

sumEuler = sum . (map euler) . mkList

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

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

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

Но (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 (g x) = (f . g) x

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

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

Стиль в вашем примере называется " point-free " стиль - аргументы функции опущены. Это делает для более ясного кода во многих случаях. (Может быть трудно впасть в первый раз, когда вы видите это, но вы привыкнете к нему через некоторое время. Это распространенная идиома Хаскелла.)

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

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

Другие советы

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

a . b

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

sumEuler = sum . (map euler) . mkList

точно такой же как

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

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

sum - это функция в Прелюдии на Haskell, а не аргумент 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.

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

Карта

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

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

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

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

  

Оператор точек в Хаскеле

     

Я пытаюсь понять, что делает оператор точки в этом коде на 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
(.) f g = \x -> f (g x)

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

Написать

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

  

(f & # 8728; g) (x)

который можно прочитать " f, составленный с помощью g " ;.

Итак, в Хаскеле, f & # 8728; g или f, составленные с помощью g, можно записать так:

f . g

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

То есть, поскольку (f & # 8728; g) & # 8728; h эквивалентно f & # 8728; (g & # 8728; h), мы можем просто написать f & # 8728; г & # 8728; ч.

Возвращаясь назад

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

sumEuler = sum . map_euler . mkList

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

sumEuler = \x -> sum (map_euler (mkList x))
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top